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

news/2024/10/14 11:57:05

TowardsDataScience 博客中文翻译 2020(九十)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

Python 中的打包:工具和格式

原文:https://towardsdatascience.com/packaging-in-python-tools-and-formats-743ead5f39ee?source=collection_archive---------5-----------------------

9 个问题的 16 种解决方案——你知道哪些?

由作者创建

虚拟环境是一个隔离的 Python 环境。它有自己安装的site-packages,可以不同于系统site-packages。别担心,我们稍后会更详细地讨论。

看完这篇文章,你就明白下面这些工具是什么了,它们解决了哪些问题:pip,pyenv,venv,virtualenv,pipx,pipenv,pip-tools,setup.py,requirements.txt,requirementst.in,Pipfile,Pipfile.lock,twine,poem,flint,hatch。

包装类型

对于本文,您需要区分两种类型的(打包)代码:

  • 由其他库或应用程序导入。库不会自己运行;它们总是由应用程序运行。Python 中库的例子有 Numpy,SciPy,Pandas,Flask,Django,点击,
  • 应用执行。Python 应用的例子有 awscli 、 Jupyter (笔记本)、任何用 Flask 或 Django 创建的网站。

你可以进一步区分它们,例如库和框架。或者命令行应用程序、具有图形用户界面的应用程序、服务等等。但是对于本文,我们只需要区分库和应用程序。

请注意,有些应用程序还包含可以导入的代码,或者有些库具有作为应用程序提供的部分功能。在这些情况下,您可以将它们用作库(包括项目中的代码)或应用程序(只是执行它们)。你是指挥官。

基础知识:pip、站点包和提示符

Python 将pip作为默认的包管理器。你像这样使用它:

pip install mpu

当您运行它时,您应该会看到以下消息:

Collecting mpuUsing cached [https://files.pythonhosted.org/packages/a6/3a/c4c04201c9cd8c5845f85915d644cb14b16200680e5fa424af01c411e140/mpu-0.23.1-py3-none-any.whl](https://files.pythonhosted.org/packages/a6/3a/c4c04201c9cd8c5845f85915d644cb14b16200680e5fa424af01c411e140/mpu-0.23.1-py3-none-any.whl)
Installing collected packages: mpu
Successfully installed mpu-0.23.1

为了能够向您展示输出和我插入的内容,我开始了包含我用$输入的命令的行:

$ pip install mpu
Collecting mpuUsing cached [https://files.pythonhosted.org/packages/a6/3a/c4c04201c9cd8c5845f85915d644cb14b16200680e5fa424af01c411e140/mpu-0.23.1-py3-none-any.whl](https://files.pythonhosted.org/packages/a6/3a/c4c04201c9cd8c5845f85915d644cb14b16200680e5fa424af01c411e140/mpu-0.23.1-py3-none-any.whl)
Installing collected packages: mpu
Successfully installed mpu-0.23.1

这个$叫做提示。在 Python 内部,提示是>>>:

$ python
>>> import mpu
>>> mpu.__file__
'/home/moose/venv/lib/python3.7/site-packages/mpu/__init__.py'

这个命令显示了软件包mpu的安装位置。默认情况下,这是系统的 Python 位置。这意味着所有 Python 包共享同一套已安装的库。

问题 1:需要不同的 Python 版本

我们安装了 Python 3.6,但是应用程序需要 Python 3.8。我们无法升级我们的系统 Python 版本,例如,因为我们缺少管理员权限,或者因为其他东西会损坏。

解决方案:pyenv

Pyenv 允许你安装任何你想要的 Python 版本。您还可以使用pyenv在 Python 环境之间轻松切换:

$ python --version
Python 3.6.0$ pyenv global 3.8.6$ python --version
Python 3.8.6$ pip --version
pip 20.2.1 from /home/math/.pyenv/versions/3.8.6/lib/python3.8/site-packages/pip (python 3.8)

更多信息,请阅读我的文章Python 开发初学者指南。详细安装说明,直接去【pyenv 官方网站。

问题 2:包装和配送大楼

你通常不仅仅使用裸 Python。作为开发者,我们站在巨人的肩膀上——整个免费软件生态系统。在 Python 的初期,人们只是复制文件。Python 文件在导入时也称为模块。如果我们在一个带有__init__.py的文件夹中有多个 Python 文件,它们可以互相导入。这个文件夹被称为。包可以包含其他包——也有__init__.py的子文件夹,然后被称为子包

复制文件和文件夹不方便。如果该代码的作者进行了更新,我可能需要更新几十个文件。我需要在第一时间知道是否有更新。我可能还需要安装数百个依赖项。通过复制粘贴来做这件事将是地狱。

我们需要一种更方便的方式来分发这些包。

解决方案:来源分配

包装系统需要三个核心组件:

  • 包格式:Python 中最简单的格式叫做源码分发。它本质上是一个具有特定结构的 ZIP 文件。该文件的一个重要部分是可以指定包的依赖关系。它还应该包含其他元数据,比如包的名称、作者和许可信息。
  • 软件包管理器:安装软件包的程序。pip 在 Python 中安装包。
  • 软件仓库:包管理者可以寻找包的中心位置。在 Python 生态系统中,pypi.org是公共的。我甚至不知道还有其他公开的。当然,您可以创建私有的。

如前所述,我们需要一种方法来指定元数据和依赖关系。这是通过setup.py文件完成的。它通常看起来像这样:

from setuptools import setupsetup(name="my_awesome_package",version="0.1.0",install_requires=["requests", "click"]
)

您可以使用更多的版本说明符,例如:

numpy>3.0.0  # 3.0.1 is acceptable, but not 3.0.0
numpy~=3.1   # 3.1 or later, but not version 4.0 or later.
numpy~=3.1.2 # 3.1.2 or later, but not version 3.2.0 or later.

为了创建源分布,我们运行

$ python setup.py sdist

我不太喜欢setup.py文件,因为它是代码。对于元数据,我更喜欢使用配置文件。Setuptools 允许使用一个setup.cfg文件。您仍然需要一个 setup.py,但它可以简化为:

from setuptools import setupsetup()

然后你就有了如下的setup.cfg文件。有关于 setup.cfg 格式的文档。

[metadata]
name = my_awesome_packageauthor = Martin Thoma
author_email = [info@martin-thoma.de](mailto:info@martin-thoma.de)
maintainer = Martin Thoma
maintainer_email = [info@martin-thoma.de](mailto:info@martin-thoma.de)# keep in sync with my_awesome_package/__init__.py
version = 0.23.1description = Martins Python Utilities
long_description = file: README.md
long_description_content_type = text/markdown
keywords = utility,platforms = Linuxurl = [https://github.com/MartinThoma/mpu](https://github.com/MartinThoma/mpu)
download_url = [https://github.com/MartinThoma/mpu](https://github.com/MartinThoma/mpu)license = MIT# [https://pypi.org/pypi?%3Aaction=list_classifiers](https://pypi.org/pypi?%3Aaction=list_classifiers)
classifiers =Development Status :: 3 - AlphaEnvironment :: ConsoleIntended Audience :: DevelopersIntended Audience :: Information TechnologyLicense :: OSI Approved :: MIT LicenseNatural Language :: EnglishOperating System :: OS IndependentProgramming Language :: Python :: 3.7Programming Language :: Python :: 3.8Programming Language :: Python :: 3.9Topic :: Software DevelopmentTopic :: Utilities[options]
packages = find:
python_requires = >=3.7
install_requires = requestsclick[tool:pytest]
addopts = --doctest-modules --ignore=docs/ --durations=3 --timeout=30
doctest_encoding = utf-8[pydocstyle]
match_dir = mpu
ignore = D105, D413, D107, D416, D212, D203, D417[flake8]
max-complexity=10
max_line_length = 88
exclude = tests/*,.tox/*,.nox/*,docs/*
ignore = H301,H306,H404,H405,W503,D105,D413,D103[mutmut]
backup = False
runner = python -m pytest
tests_dir = tests/[mypy]
ignore_missing_imports = True

问题 3:安全上传

您希望将包安全地上传到 PyPI。你需要认证,你想确定没有人篡改你的包。

解决方案:缠绕

通过pip install twine安装绳,您可以上传您的分发文件:

twine upload dist/*

问题 4:依赖冲突

你想在版本1.2.3中安装需要库requestsyoutube-downloader,在版本3.2.1中安装需要库requestsvimeo-downloader。因此库requests是两个应用程序的依赖项。这两个应用程序都需要用 Python 3.8 来执行。这是一个问题,因为两个应用程序都将requests存储在同一个site-packages目录中。一旦你安装了一个版本,另一个就没了。您需要两个不同的环境来运行这两个应用程序。

python 环境是 Python 可执行文件、pip 和一组已安装的软件包。不同的环境是相互隔离的,因此不会相互影响。

我们通过创建虚拟环境来解决这种依赖性冲突。我们称之为虚拟,因为它们实际上共享 Python 可执行文件和其他东西,比如 shells 的环境变量。

解决方案:venv

Python 有 venv 模块,碰巧也是可执行的。您可以创建和使用一个全新的虚拟环境,如下所示:

$ python -m venv my-fresh-venv
$ source my-fresh-venv/bin/activate(my-fresh-venv)$ pip --version
pip 20.1.1 from /home/moose/my-fresh-venv/lib/python3.8/site-packages/pip (python 3.8)

环境之所以被称为“新鲜”,是因为里面什么都没有。在source-调用activate脚本后安装的所有东西都将被安装在这个本地目录中。这意味着当你在一个这样的虚拟环境中安装youtube-downloader而在另一个虚拟环境中安装vimeo-downloader时,你可以同时拥有两者。你可以通过执行deactivate走出虚拟环境。

如果你想了解更多细节,我推荐你阅读 Python 虚拟环境:初级读本。

问题 5:不方便

您仍然需要一直在虚拟环境之间切换,这很不方便。

解决方案:pipx

pipx 自动将软件包安装到它们自己的虚拟环境中。它还会自动执行该环境中的应用程序😍

注意:这只对应用有意义!您需要在与应用程序相同的环境中使用库。所以永远不要用 pipx 安装库。用 pipx 安装应用程序(间接安装库)。

问题 6:更改第三方代码

作为一名应用程序开发人员,我想确保我的应用程序能够正常工作。我想独立于我使用的第三方软件的潜在突破性变化。

比如,想想 1.2.3 版本中需要requestsyoutube-downloader。在某些时候,可能是在开发期间,那个版本的请求可能是最新的版本。然后youtube-downloader的开发就停止了,但是requests一直在改。

解决方案:依赖固定

给出您想要安装的确切版本:

numpy==3.2.1
scipy==1.2.3
pandas==4.5.6

然而,如果你在setup.py中这样做,这本身就有一个问题。您将在相同环境中的其他软件包上强制使用这个版本。Python 在这里相当混乱:一旦另一个包在同一环境的另一个版本中安装了您的一个依赖项,它就会被简单地覆盖。您的依赖项可能仍然有效,但是您没有得到预期的版本。

对于应用程序,您可以像这样将依赖项固定在setup.py中,并告诉您的用户使用pipx来安装它们。这样你和你的用户都会很开心💕

对于库,您不能这样做。根据定义,库包含在其他代码中。可能包含大量库的代码。如果它们都固定了它们的依赖关系,那么很可能会出现依赖冲突。如果开发的库本身有几个依赖项,这会使库开发变得困难。

通常的做法是不在setup.py文件中固定依赖关系,而是创建一个带有固定依赖关系的平面文本文件。 PEP 440 在 2013 年定义了格式或要求文件。它通常被称为requirements.txtrequirements-dev.txt,通常看起来像这样:

numpy==3.2.1
scipy==1.2.3
pandas==4.5.6

您还可以根据 PEP 440 指定下载包的位置(例如,不仅是名称,还有 git 存储库)。

requirements.txt 中的包(包括它们的依赖项)可以与

$ pip install -r requirements.txt

问题 7:改变传递依赖关系

想象你写的代码依赖于包foobar。这两个包本身也可能有依赖关系。这些依赖被称为代码的传递依赖。它们是间接依赖关系。你需要关心的原因如下。

假设发布了多个版本的foobarfoobar恰好都有一个依赖关系:fizz

情况是这样的:

foo 1.0.0 requires fizz==1.0.0
foo 1.2.0 requires fizz>=1.5.0, fizz<2.0.0
foo 2.0.0 requires fizz>=1.5.0, fizz<3.0.0bar 1.0.0 requires fizz>2.0.0
bar 1.0.1 requires fizz==3.0.0fizz 1.0.0 is available
fizz 1.2.0 is available
fizz 1.5.0 is available
fizz 2.0.0 is available
fizz 2.0.1 is available
fizz 3.0.0 is available

你可能想说“我需要foo==2.0.0bar==1.0.0。有两个问题:

  1. 依赖满足可能很难:客户需要弄清楚这两个需求只能由fizz==2.0.0fizz==2.0.1来满足。这可能很耗时,因为 Python 源代码发行版没有很好地设计,也没有很好地公开这些信息(示例讨论)。依赖关系解析器实际上需要下载包来找到依赖关系。
  2. 中断传递性变更:包 foo 和 bar 无法声明它们的依赖关系。你安装了它们,事情就正常了,因为你碰巧有foo==2.0.0bar==1.0.0fizz==2.0.1。但是过了一会儿,fizz==3.0.0就放出来了。不用告诉pip要安装什么,它就会安装最新版本的fizz。之前没有人测试过,因为它不存在。你的用户是第一个,这对他们来说是坏消息😢

解决方案:固定传递依赖关系

您还需要找出可传递的依赖关系,并准确地告诉 pip 要安装什么。为此,我从一个setup.pyrequirements.in文件开始。requirements.in文件包含了我所知道的必须实现的内容——它与 setup.py 文件非常相似。与setup.py文件不同,它是一个平面文本文件。

然后我使用 pip-tools 中的pip-compile来寻找传递依赖关系。它将生成如下所示的requirements.txt文件:

#
# This file is autogenerated by pip-compile
# To update, run:
#
#    pip-compile setup.py
#
foo==2.0.0   # via setup.py
bar==1.0.0   # via setup.py
fizz==2.0.1  # via foo, bar

通常情况下,我有以下内容:

  • setup.py :定义抽象依赖和已知的最低版本/最高版本。
  • requirements.txt :我知道的一个版本组合在我的机器上工作。对于我控制安装的 web 服务,这也用于通过pip install -r requirements.txt安装依赖项
  • 需求-开发在中:我使用的开发工具。pytest、flake8、flake8 插件、mypy、black 之类的东西……看我的静态代码分析贴。
  • requirements-dev.txt :我使用的工具的确切版本+它们的传递依赖。这些也安装在 CI 管道中。对于应用程序,我还在这里包含了requirements.txt文件。请注意,我创建了一个包含了requirements.txt的组合requirements-dev.txt。如果我在安装requirements-dev.txt之前安装requirements.txt,它可能会改变版本。这意味着我不会对完全相同的包版本进行测试。如果我在requirements-dev.txt之后安装requirements.txt,我可以为开发工具破坏一些东西。因此我通过
    pip-compile --output-file requirements-dev.txt requirements.txt创建了一个组合文件

如果你想确定完全一样,你也可以加上--generate-hashes

问题 8:非 Python 代码

像 cryptography 这样的包都有用 c 写的代码,如果你安装了 cryptography 的源代码发行版,你需要能够编译那些代码。您可能没有安装像 gcc 这样的编译器,编译需要相当多的时间。

解决方案:构建的发行版(轮子)

软件包创建者也可以上传构建的发行版,例如作为 wheels 文件。这可以防止你自己编译东西。事情是这样做的:

$ pip install wheels
$ python setup.py bdist_wheel

例如, NumPy 这样做:

pypi.org 的截图是作者拍摄的。

问题 9:构建系统的规范

Python 生态系统非常依赖 setuptools。不管 setuptools 有多好,总会有人们遗漏的功能。但是我们有一段时间不能改变构建系统。

解决方案:pyproject.toml

人教版 517 和人教版 518 规定了pyproject.toml文件格式。看起来是这样的:

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

是的,不多。它告诉 pip 构建您的包需要什么。但这是迈向更大灵活性的良好一步。

其他工具,像 poem 和 black,使用这个文件为他们的pyproject.toml配置,类似于flake8pytestpylint和更多允许你添加配置到setup.cfg

Giorgio Trovato 在 Unsplash 上拍摄的照片

荣誉奖

本节中的工具相对广泛,但是到今天为止,它们并没有真正解决上面的工具没有解决的任何问题。它们可能比其他的更方便使用。

virtualenv 和 virtualenvwrapper

第三方工具 virtualenv 存在于核心模块 venv 之前。它们并不完全相同,但对我来说,venv已经足够好了。如果有人能告诉我一个问题的解决方案是 virtualenv(而不是 venv ),我会很高兴🙂

virtualenvwrapper 扩展 virtualenv。

pipenv

Pipenv 是一个依赖管理和打包的工具。它介绍了两个新文件:

  • Pipfile :一个 TOML 文件。它的内容在思想上类似于requirements.in的内容:抽象依赖。
  • Pipfile.lock :一个 TOML 文件。它的内容在思想上类似于requirements.txt的内容:固定的具体依赖,包括可传递的依赖。

本质上,它包装了 venv。

诗意

诗歌是一个依赖管理和打包的工具。它结合了许多工具,但其核心功能与 pipenv 相同。主要区别在于它使用了pyproject.tomlpoetry.lock而不是PipfilePipfile.lock。霜明写了一篇诗与 pipenv 的详细比较。

诗歌包装或替换的项目有:

  • 脚手架 : poetry new project-name vs 千篇一律
  • 建筑分布 : poetry build vs python setup.py build sdist_build
  • 依赖管理 : poetry add foobar vs 手动编辑 setup.py / requirements.txt 文件。然后,poems 将创建一个虚拟环境,一个与Pipfile.lock概念相同的poetry.lock文件,并更新pyproject.toml。你可以在下面看到一个例子。它们使用自己的依赖部分,这与其他任何部分都不兼容。我希望他们搬到 PEP 631(更新见期)。
  • 上传到 PyPI : poetry publish vs twine upload dist/*
  • 凹凸版 : poetry version minor vs 手动编辑setup.py / setup.cfg或使用凹凸版。⚠️尽管诗歌在包含一个版本的脚手架中生成了一个__init__.py,但poetry version并没有改变这一点!

它背离了指定依赖关系的事实上的标准setup.py / setup.cfg。相反,诗歌期望依赖关系在它的配置中:

[tool.poetry]
name = "mpu"
version = "0.1.0"
description = ""
authors = ["Martin Thoma <[info@martin-thoma.de](mailto:info@martin-thoma.de)>"]
license = "MIT"[tool.poetry.dependencies]
python = "^3.8"
awscli = "^1.18.172"
pydantic = "^1.7.2"
click = "^7.1.2"[tool.poetry.dev-dependencies]

我希望他们也能实现 PEP 621 和 PEP 631 ,在[project]部分给元数据和依赖项一个正式的位置。让我们看看,也许他们改变了那个。

有些人喜欢有一个什么都做的工具。我宁愿选择 Unix 哲学:

让每个程序做好一件事。要做一项新的工作,就要重新构建,而不是通过添加新的“特性”使旧的程序变得复杂。

由于诗歌结合了很多工具,它没有做什么也很重要:

  • 包管理:你还需要 pip。并且 pip 支持 pyproject.toml 。
  • 脚手架 : Cookiecutter 有很多模板。我自己创建了两个:一个用于典型的 Python 项目,一个用于 Flake8 插件。
  • Setup.py :你可能不需要自己创建一个,但是 poems 会为你创建一个 Setup.py 文件。看看发行版文件就知道了。

我还应该指出,诗歌有一个超级好的命令行界面和视觉愉悦的网站。

舱口

孵化也旨在替代相当多的工具:

  • 脚手架 : hatch new project-name vs 千篇一律
  • 凹凸版 : hatch grow minor vs 手动编辑setup.py / setup.cfg或使用凹凸版
  • 运行 pytest : hatch test vs pytest
  • 创建虚拟环境 : hatch env my-venv vs python -m venv my-venv
  • 安装包 : hatch install package vs pip install package

我在尝试孵化时犯了几个错误。

菲丽

Flit 是一种将 Python 包和模块放在 PyPI 上的方法。它是 setuptools 的第三方替代品。在这个意义上,它类似于 setuptools + twine 或诗歌的一部分。

康达

Conda 是 Anaconda 的包管理器。它比 pip 更强大,可以构建/安装任意语言的代码。有了pyproject.toml,我想知道康达在未来是否有必要🤔

红鲱鱼

  • 这是在 Python 中安装东西的最古老的方法。它类似于pip,但是你不能(轻易)卸载用easy_install安装的东西
  • distutils:虽然是核心 Python,但是已经不用了。setuptools更强大,到处安装。
  • 我不确定那是否曾经发生过?
  • pyvenv:弃用,支持venv

摘要

  • pip是蟒蛇的包经理。它转到 Python 包索引PyPI.org 来安装你的包和它们的依赖项。
  • 抽象依赖可以用 setup.py、requirements.in、Pipfile 或者 pyproject.toml 来表示,你只需要一个。
  • 具体的依赖关系可以用 requirements.txt,Pipfile.lock,或者 poetry.lock 来表示,你只需要一个。
  • 构建包是用 setuptools 或者诗歌完成的。
  • 上传包是用麻线或者诗歌完成的。
  • 虚拟环境由 venv 或 poem/pipenv/hatch/conda 创建
  • pipx 如果要安装应用的话很酷。不要用在图书馆。

付费搜索增量

原文:https://towardsdatascience.com/paid-search-incrementally-adc5ea284279?source=collection_archive---------21-----------------------

重新思考你的目标并找到最佳投标水平——一份商业解释和一份操作指南

许多广告商和数字营销专业人士通常致力于实现每笔销售的目标成本,同时最大化他们为企业带来的客户数量或销售额。今天,我们将挑战在付费搜索领域实现这些目标的最佳方式,引入增量概念。为此,我们不仅要解释背后的商业理性和理论,还要提出在渐进框架中操作的实际步骤,并提供代码样本,以高效的方式应对挑战。

让我们首先将增量定义为一个特定行为对总产出(即成本、销售、收入、利润或其他)变化的影响。为了理解增量,我们必须意识到总有一个基线情况,你想要对照它来衡量任何给定行为的影响:

  • 场景 1 — 一个行动是完全递增的 —最终,如果基线场景是几乎什么都没有的状态,那么所有行动都是 100%递增的。例如,拥有一个电子商务公司的网站是 100%的增量。没有它就没有销售或收入。
  • 场景 2 — 一项行动是部分递增的 —并非所有行动都像上面的行动一样重要。例如,考虑一家公司在谷歌上购买关于他们自己品牌的广告空间,如果他们不这样做,那么一些潜在客户会点击他们竞争对手的付费广告链接;然而,他们不能说点击自己广告的人带来的收入是 100%递增的,因为有些人可能会通过自己品牌的 SEO 有机链接来访问他们的网站,跳过竞争对手的付费广告。(注意:我并不主张不对你的品牌竞价,许多公司这样做是因为它们通常是廉价的点击,他们害怕竞争会吓跑一些自然客户)
  • 场景 3 — 一个动作是部分递增的,你想知道做这个动作有多少是最佳的 —例如,想象一家餐馆,试图计算他们的菜单上应该有多少选项。当然,答案往往不止一个或两个,以增加选择和满足不同的客户群,然而,在这一点上,一个额外的菜单项增加变化的好处被不得不管理额外的食物库存,培训他们的厨师制作这样的食谱和增加厨房协调的难度的成本所超过,以在一个给定的服务中在不同的菜肴之间跳跃?可能许多餐馆都希望有一个工具来帮助他们解决这个优化问题。
  • 场景 4 — 一个行动根本不是增量 —一个简单的例子是给你的员工发白色笔记本而不是黑色笔记本:这个行动在任何给定的时间点都不会增加员工的生产力。然而,有时非增量行动更难识别。例如,你向现有客户展示一些脸书广告,他们最终会在某个时候再次购买你的产品(这是有关联的)。虽然,他们可能会在任何情况下购买你的商品(相关性并不意味着因果关系),甚至他们中的一些人最终会再次从你那里购买,但他们对你公司的过度沟通感到不安,最终不会再回到你的网站或商店(在这种情况下,你的行动将是负增量)。

在继续之前,有一个小提示:关于付费搜索增量的含义,一个合理的预期可能是追求理解作为一个整体的渠道的增量价值(即,如果我们完全关闭了 ppc,会发生什么?一些潜在客户还会通过其他营销渠道找到我们吗?).尽管对于一些公司来说,这可能是一个非常有见地的研究,但这不是本文今天要探讨的内容。相反,本文将关注我们在场景 3 中描述的内容及其在付费搜索领域的应用。希望这能有助于你思考你的 PPC 目标,以及如何衡量实现这些目标的最佳出价。

因此,就像在餐馆优化他们应该拥有的菜单项目数量的例子中一样,一些谷歌广告广告可能会对你的业务有益和有利可图,而太多的谷歌广告广告开始对你的公司造成轻微的损失。这篇文章提出了一个框架,用于寻找谷歌广告的最佳数量,同时保持一种递增的心态,并远离一种平均的思维方式。这意味着在优化成熟度 2 和 3 之间进行如下所述的过渡(这可能与优化成熟度 1 和 2 之间的过渡一样重要和基本):

  • 优化成熟度 1 — *公司目标—*SEM 渠道经理确保客户大致达到每次转化的总体目标,并且广告支出的回报符合高层管理人员或客户的期望。活动的多样性要么是有限的,要么是跨活动的每次转换的实际成本跨度非常大。
  • 优化成熟度 2 — *平均值—*SEM 经理仍然确保客户的广告支出回报符合预期,但同时确保其拥有一个稳健的客户结构,其中大量活动在所有活动中实现相似的每次转化成本。其背后的基本原理是,首先,平均每次转化成本高于目标的活动对公司来说是无利可图的,其次,当所有活动都达到目标时,转化量最大化,而一些活动低于目标,另一些活动高于目标(即使在一天结束时,这两种情况都导致总体账户达到目标)。在确保上述内容后的第二步,SEM 经理通常还会确保除活动级别之外的其他“分割”客户的方式在每次转换的平均成本方面也是相同的(例如设备类型、主要位置、在许多活动中重复出现的广告组类型等)。).大多数公司都是在这种 ppc 优化成熟度水平上运营的。
  • 优化成熟度 3 — 增量— 在此框架下运营的公司明白,他们的平均目标和指标只是冰山一角。关键的思维转变是,他们从“重新定义了这个问题:我每次转换的平均成本是多少?“转换”我愿意在任何特定转换上花费的最大金额是多少?”。他们还了解收益递减,并且收益递减取决于许多因素:他们知道每次转化的平均成本相同的两个活动的每次转化的增量成本可能非常不同,如果他们多花一英镑或一美元,他们不会在这两个活动中平均分配,而是将它应用于每次转化的增量成本较低的一个活动。然而,要将这样的框架付诸实践,他们首先要做的不同的事情是生成他们自己的数据集,因为增量指标并不容易获得,这通常涉及到许多跨团队的合作(并且他们决不会低估所有相关团队之间沟通、协调和购买的重要性)。没有这样的努力,这个框架将永远只是一个理论上的练习。最后,一旦解锁,他们通过使用他们的新指标、报告和营销业务目标,从理论到实践,从平均值到增量。

但是,我们所说的平均值相同但增量经济学不同的运动是什么意思呢?让我们考虑下面的例子:对于 ABC 和 XYZ 的活动,你已经设置了 6 的目标 cpa(这里假设智能竞价,但是如果你运行关键字级别手动竞价,应该没有什么不同),并且谷歌能够为你的每个活动以该平均成本获得 100 次转换。如果不考虑增量,你可能没有理由在优化每个活动时采取不同的行动。然而,在后台可能发生的情况是,活动 ABC 能够以平均价格 5.8 获得 80 次转化,并以平均价格 6.8 获得额外的 20 次转化(总 100 次转化的平均 cpa 仍然是 6/次转化) 然而,XYZ 战役可以让你以平均 4 英镑的价格获得 80 次转换,然后找些空闲时间让你以平均 14 英镑的价格获得额外的 20 次转换(总转换的平均 cpa 仍然是 6 英镑——是的,这种情况可能发生,而且确实在很多场合一直在发生! ).基本上,在一种情况下,你以合理的价格获得了额外的 20 次转换,而在另一种情况下,价格可能会让你赔钱,这总结了为什么平均值往往隐藏了一半的情况。我们用一个图表来说明这个观点,以此来结束这一部分:

每次转换的边际成本与平均成本

在这个阶段,我们已经奠定了理论框架,关于为什么 PPC 增量是重要的,但我们还没有提出一个实际的方法来操作在这个优化成熟度水平下,这可能是本文的主要观点。尽管这比在平均框架下操作要困难,因此很少有公司采用它。使用平均值的好处是,数据通常很容易使用,并且不需要额外的步骤来生成数据。Google ads 将为您提供详细的花费和转化数据,您可以根据这些数据轻松计算出您在账户本身或账户的几乎任何*【片段】*(每个活动、广告组、设备、设备和活动的组合、位置、受众等)上的平均每次转化成本。).如果你想在一个增量框架上操作,你必须弄清楚你想生成哪些数据,生成它,并确保其质量和准确性。

那么,你如何对你的 ppc 账户进行增量测试呢?是的,我说测试是因为一方面,对于许多人来说,ppc 增量可能还没有实现,另一方面,ppc 增量本身确实需要测试。当我们早些时候给出一个例子,在你的 100 次转换中,总成本为 600,你可能会以 4 的成本获得 80 次,以 14 的成本获得额外的 20 次,我们没有提到实际上有一种方法可以确定(或不确定)(至少从统计上来说)。这个载体很可能就是你所知道的谷歌广告的草稿和实验。该工具将允许您 A/B 测试您帐户中的任何活动,将搜索流量平均分配给对照和变体(或 google ads 行话中的原始和草稿活动),并查看如果您有草稿而不是原始活动,您的指标(花费和转化率)会发生什么。您的草案和原始活动之间的差异将为您提供增量支出和增量转换。不过要小心,如果我们不把统计显著性等同于我们的测试,它会像什么都不做一样提供信息。此外,您可能很难在活动级别获得统计显著性,并且您必须在测试中降低粒度(即,考虑从客户/活动组/组合级别开始)。

因此,它最终归结为以下步骤(现在我们进入文章的实际应用):

  1. 情况分析
  2. 大规模创建多个草稿和实验
  3. 监控测试的完整性
  4. 以适当的方式收集数据,并准备好进行测量。
  5. 评估测试
  6. 探索性分析
  7. 总结并准备未来的内分泌测试。

1)情景分析

这是计划、玩弄数字和预测阶段。像任何好的实验一样,你应该从一个假设开始,这个假设应该是可操作的(即,它的确认与否应该使你采取行动 A 或行动 B),并且可以以良好的准确度进行测量(即,你必须能够生成足够的数据来得出具有统计意义的结论,并且不应该存在任何技术、商业或业务障碍来阻止你生成这样的数据)。让我们回到我们的例子,我们有一个点击付费帐户,产生了 100 个转换,平均每次点击费为 6。在这种情况下,一个好的假设的例子可能是:

  • 你想知道你的增量转换成本是否超过 15 英镑(例如,因为你在 15 英镑盈亏平衡,或者因为你想要至少 2 倍的边际 ROAS 来补偿你所有的其他成本)。
  • 如果你证实了你的假设(每 conv 的递增转换率> 15),你将采取的行动是把你的出价降低到你在这个实验中测试的相同出价水平。
  • 如果你否定了你的假设(增量转换< 15 每 conv),你将采取的行动是保持你的出价水平。

考虑到这一点,现在您将运行一些场景来处理测试的变量:

  • 测试的潜在指标:漏斗下端的转换可能会提供您最感兴趣的答案,但是漏斗上端的转换更频繁,因此意味着测试持续时间更短。你越怀疑不同的出价对你的 ppc 帐户吸引的访问者类型的影响,你就越有理由努力将漏斗下端的转化作为你的测试指标,否则漏斗上端的转化可能就能做到;
  • 出价水平的变化:测试彼此更接近的出价水平更有意思,比如 10%的变化,但你可能没有足够的数据来准确验证这样小的差异;
  • 假设当你的出价按照上面定义的水平改变时,花费和转化率会发生什么:如果你降低出价,你的花费水平自然也会降低,但是会降低多少呢?你应该提前提出一些假设,并检查“如果你在测试结束时观察到这种差异”,这些假设会对你的估计和信心水平产生什么影响。您希望事先确保测试的设计足够稳健,能够承受不同的结果,并且仍然能够为您提供最初问题的答案:我的每次转换的增量成本是高于还是低于 15?为此,你会希望你的置信区间不重叠 15。
  • 运行测试的时间:时间越长,您收集的数据越多,您的置信区间变得越小,但是运行测试总是有相关的成本,至少是牺牲的转换数量或不运行其他测试的机会成本。你的问题的答案越重要,你就越愿意延长测试时间。

你为上述 4 个变量考虑的选项越多,你最终得到的情景就越多,所以我们希望在综合的情景组合和不被它们淹没之间取得平衡。回到我们的例子,我们自己也创建了一些场景。我们考虑了两个指标:投标级别的两种变化;当改变每个投标级别时,对花费和转换会发生什么的两种不同假设;和两个测试持续时间。根据下表,所有这些组合导致了总共 16 种情况:

情况分析

首先需要解释的是,您将生成比“转换”数据多得多的“花费”数据,因此您的花费置信区间通常非常接近其点估计值,这意味着您的测试准确性将主要取决于您的转换数据。

其次,置信区间的计算不仅取决于您的假设,还取决于您将生成多少数据(您应该查看您的帐户历史记录,以了解在您的情况下有多少)。在“评估测试”部分,我们深入研究了置信区间计算,您也可以在场景分析中计算预期 ci 时应用这些计算。

因此,一旦我们有了所有这些,就该对我们实验的最终设计做出决定了,看一下示例中的场景,以下情况似乎是不可能的:

  • 出价 10%的变动似乎不是一个选项。即使我们运行它 2 个月,并使用销售线索作为测试指标,在我们假设花费减少 15%和转化率减少 7%的场景中,置信区间将重叠 15。在测试结束时,我们可能会处于这样一种情况,我们既不能确认也不能反驳我们的假设,因此不确定是采取行动 A 还是行动 b。
  • 基于 1 个月的购买量运行测试似乎也不在考虑范围之内(在我们的支出下降 50%和转化率下降 25%的场景中,置信区间与 15 重叠很多—[8.8;18.8];并且使用其他假设,置信区间刚好接近 15)

因此,我们的选择是:

  • 运行测试 1 个月,并对潜在客户进行评估(两个花费/转换假设最终都在没有重叠的置信区间 15 内)
  • 将测试持续时间延长至两个月,并将购买量转化为您的衡量指标(再次消除重叠 15)

你最终选择哪一个取决于在测试持续时间和低漏斗转化率的权衡中什么对你更重要。

2)按比例创建多个草稿和实验

此时,您已经选择了测试的设计,这是我们需要更多技术的地方,因为我们将引入代码示例来处理这一步。Python 作为选举的数据语言将会被使用,而且我们将会与 adwords API 交互。因此,首先你需要连接到你的帐户的 AdWords API。如果你之前没有用过 API,你首先要做的是获取一个开发者令牌;一个谷歌客户端 ID(这不同于客户端客户 ID——你实际上在谷歌广告用户界面上看到的一个类似于这个的数字:562–425–3085);谷歌客户端机密;和谷歌刷新令牌。在这里有关于如何开始使用 adwords API 并生成上述所有内容的非常有用的文档。

如果您成功完成了上述操作,那么下面的脚本应该会将您连接到 adwords API:

Google Adwords —连接到 API

接下来你可能要做的事情与预算有关。如果您的帐户中没有使用任何共享预算,您可以忽略这一点,但我敢打赌,至少您的一些活动是共享预算的。如果这确实是你的帐户的情况,那么下一位设置来解决使用草案和实验的缺点之一:你不能为使用共享预算的活动创建草案。这意味着您必须创建单独的预算,并将它们分配到您的活动中。幸运的是,您也可以通过编程来实现这一点,这将为您在您的客户中提议进入增量测试的所有活动节省大量时间。一旦您决定了每个活动的合理预算金额,以下脚本将帮助您创建这些预算:

Google Adwords API —为活动创建和分配预算

现在是介绍为什么 google 可能将这个特性命名为 Drafts 和 Experiments,而不是 juts Drafts 或只是 Experiments 的好时机,因为创建草稿是列表中的下一个。简而言之,草稿在创建时是现有活动的副本,它将始终与其原始活动保持链接(即不能独立运行),并将看到它的某些组件相对于原始活动发生变化(理论上你不必这样做,但这似乎毫无意义);而实验是将确定在何种情况下以及在多长时间内在草案和原始活动之间进行测试的设置(流量的分割是什么,如果分割是基于 cookie 或搜索,开始日期是什么,等等。).草稿是一场战役,实验是背景。

因此,列表中的下一步是创建草稿,这可以通过运行下面的脚本来完成:

Google Adwords API —创建草稿

当然,最需要注意的是这个create_draft()函数返回的信息,因为我们以后需要它来修改征兵活动和创建实验。这正是我们接下来要做的:改变征兵活动。

正如在前面的例子中,我们将认为你正在操作一个 target_cpa 智能投标策略,并且你想知道当你把你的目标降低 30%时会发生什么。下面的代码将帮助您做到这一点。

Google Adwords API —更改目标 CPA

上面的代码做了两件事,首先,它创建了一个目标 cpa 投资组合,其目标比分配给原始活动的投资组合少 30%,其次,它将新创建的投资组合分配给我们在上一步中创建的草稿活动。不过,我们还应该记住其他一些事情:

  • 如果您的多个活动被分配到同一个投资组合,那么您不会希望为每个草稿活动创建一个投资组合。相反,更明智的方法是为共享相同目标 cpa 的每组草稿活动创建一个组合,并将该组合分配给具有相同目标的所有草稿。具体的代码会略有不同,但会遵循类似的逻辑。
  • 在一些活动中,您可能有广告组,它们有自己的单独目标。如果是这种情况,你必须确保相应的广告组的草案活动将有他们的目标下降 30%(在这个例子中)。否则,你将不会有一个公平的测试,因为一些广告组不会像其他广告组一样被丢弃。您需要一个额外的脚本来完成这个操作。

一旦完成以上工作,我们就进入了使用草稿和实验进行实验的最后一步。这并不复杂,您只需要获取由create_draft()函数返回的 draft_id 和 campaign_id,然后选择一个实验名称(理想情况下,类似于标识原始活动的一个位和标识作为该测试一部分的整组实验的一个位,例如后缀:campaign _ 123-decrease _ 30 _ test)、一个分割百分比(推荐 50%)和一个分割类型(推荐 Cookie)。下面的代码将处理这一部分的最后操作:

Google Adwords API——创建实验

3)监控测试的完整性

当你运行一个测试时,没有什么比看到它被无效更糟糕的了,尤其是因为完全不可避免的原因。这一部分是关于如果我们不小心就会出错的事情的观察点,这些事情最终会使这个测试的数据(这些增量数据集)无效,而这些数据对于我们的最终目标是如此珍贵。问题的关键在于,你的原始广告和草稿广告之间唯一不同的地方是出价水平。所以:

  • 如果您有任何团队成员或工具在整个客户范围内以系统的方式更新广告文案,请确保将相同的更改应用于原稿和草稿。
  • 如果您的登录页面由于任何原因发生变化,请确保当天结束时原始和草稿具有相同的登录页面。
  • 如果您要将出价修改量添加到您的活动中,您也需要将它们添加到草稿中。
  • 如前所述,如果你的广告活动有广告组目标,他们将不得不减少/增加相同比例的主要活动目标,你需要确保他们在整个测试中保持不变。我添加了一些示例代码,说明如何快速进行这种比较,特别是利用 adwords API:

Google Adwords API —比较广告组

  • 我想你已经明白了这一点,但为了全面起见,这里有一些其他的设置你可能要记住:预算,定位,受众,网络,广告轮换,转换,新的广告组或关键词,负面关键词,扩展。

最终,这是一个平衡,要么努力避免对你已经起草和试验的活动做很多改变;或者建立一个强大的系统,确保应用于原件的更改也应用于草稿。

最后,结束这一部分的一个额外的注意:你在选秀活动中的作品集在最初几天进入学习模式并表现得滑稽吗?如果是,请考虑将这些天从您的增量数据集中排除。

4)以适当的方式收集数据,并为测量做好准备

您已经启动了您的测试,并确保它在公平的条件下运行,接下来您要做的事情是以适合分析和评估的方式收集和准备测试数据。根据我们到目前为止所做的,我们也将借助 adwords api 来处理流程的这一步。

但首先让我问你,你听说过 fivetran 吗?如果没有,请帮你自己一个忙,直接去实现它!假设您目前正在使用 fivetran,或者您继续实现它并回到本文,我们将使用 google ads fivetran 连接器来获取我们需要的数据。另一种方法是直接使用 AdWords 查询语言(AWQL ),但是 fivetran 只需点击几下鼠标就能为我们处理所有的事情。

*因此,使用 fivetran,我们需要做的是创建一个新的 google ads 连接器,并将竞选业绩报告同步到您的选举数据库中( psst… 雪花 *是最好的一个)根据下图选择以下字段:

  • AccountDescriptiveName
  • CampaignId
  • 活动名称
  • AdNetworkType2 (测试分析不需要,但对深潜有用)
  • 日期
  • 装置(测试分析不需要,但对深潜有用)**
  • 点击(测试分析不需要,但对深潜有用)**
  • 转换策略
  • 转换值
  • 费用
  • 印象(测试分析不需要,但对深潜有用)**
  • 搜索印象分享(测试分析不需要,但对深潜有用)**

Fivetran 谷歌广告连接器

最后,一旦这些数据进入您的数据库,下面的查询将以适合测试评估的方式对其进行组织(这样的查询将作为测试评估的基础):

查询 Fivetran Google Ads 数据—用于评估的控制和测试数据

5)评估测试

在这个阶段,你的测试即将结束或者已经完成。你已经以适合分析的方式收集和准备了数据,这正是你现在要做的。但是怎么做呢?没有一种方法是正确的,但我们建议使用一种叫做 bootstrap 重采样的统计技术(这实际上与谷歌自己用来报告他们的置信区间的方法没有太大区别——尽管他们使用刀切重采样)。我们之所以需要这样做,是因为谷歌只报告单个活动实验的置信区间,所以如果你在多个活动上进行实验,你必须自己计算这些置信区间,就好像它们是一个大的活动一样,因为它们实际上都是同一个实验的一部分。

这一阶段的最终目标不仅是找出测试组和对照组之间的花费和转化率的差异(因为这相对容易,我们只需要查看两组实验的总花费和转化率),而且还要找出该差异的置信区间,从而进行重新采样。通过重新采样,我们将采用一个样本(传递冗余)替换不同日期不同活动表现的 n 个观察值,并比较测试和控制之间的差异(n 是第 4 节中提供的查询产生的总行数,即活动/日期的总组合)。我们将多次重复这一过程(通常在 1,000 到 10,000 次之间),并对每个过程比较测试和控制之间的差异。有了这组样本,我们现在可以计算这组样本的点估计值(重采样平均值的平均值)和性能方差,从而计算出我们的统计标准偏差:

***σ**x **= ( ∑ ( (xi -x) ^ 2 ) / j) ^ (½)**xi, being the mean of each resample
x,  being the point estimator (the mean of all resamples' means)
j,  being the number of resamples*

现在有了对照和试验之间的方差和观察到的差异,我们就能够计算出如此需要的置信区间:

***CI = x ± 1.64 * ( σ**x **/ n ^ (1/2) )**x,    being the point estimator (the mean of all resamples' means)
**σ**x,   the standard deviation of the samples' means
n,    the size of the sample (i.e. combinations of campaigns/days)
1.64, Zα for a 90% Confidence Interval*

最后,我们可以以 90%的置信度说,在我们的 ppc 账户中,不同竞价级别的真实性能差异位于置信区间的下限和上限之间,并相应地做出商业决策——回到我们在场景分析部分的示例,这意味着如果置信区间低于 15,我们将保持我们的竞价级别,但是,如果置信区间高于 15,我们将降低我们的竞价 30%(因为边际转换的边际成本将高于我们的盈利阈值)

使用 python 和模拟根据步骤 4 中提出的方法准备的数据集的虚拟数据集进行此类计算的实际代码如下:

转化率差异的置信区间—评估试验

如果你有兴趣了解更多关于这种重采样技术及其背后的理论,我真的推荐这篇文章。

6)探索性分析。

这可能是整个旅程中最有趣、最快乐的阶段之一。你已经成功地确定了从投标级别 x 到投标级别 y 的增量价值,并为你的企业提供了关键信息,使其能够根据你的增量支出的增量价值来决定是保持还是改变投标级别。如果您是第一次这样做,或者如果您没有生成大量的转换数据,您可能已经为整个客户这样做了;或者你更进一步,对多个投资组合、活动组或其他进行了测试(这意味着你的测试实际上是一组测试,并且你相应地对它们中的每一个采取了行动)——然而,为了简单起见,在这一部分中,我们将假设你进行了总体账户测试。

然而,有一个明确的假设,我们想回答的是这个风险的主要目标,一个 ppc 增量测试也应该创造许多副产品,你不会想忽视。副产品可能需要计划(例如,如果你有目的地将你的活动细分为目标位置,即此刻下雨的位置和不下雨的位置——在大多数情况下很牵强,但例如,如果你有挡风玻璃业务或销售防滑链,这可能对你很重要),但通常它们会出现在一个或多个 adwords 报告类型中,在许多情况下,它们甚至是无意的,只有在仔细的测试后分析后才能发现。让我们更深入地了解第二个选项:我将更深入地给出几个示例,此外还会建议一个可能对您客户的不同增量级别产生有趣影响的因素列表,您的工作是查看所有这些因素,并找出哪些因素对您的业务更具决定性。

例 1:印象分享在增量中起着关键作用。想象你在你的网站上卖两种 t 恤——一种蓝色的和一种红色的(每种都有一个 ppc 活动)。它们的售价相同,但蓝色 t 恤的转换率是 40%,红色是 10%,因此你愿意为蓝色 t 恤的点击付费比红色 t 恤的点击多支付 4 倍。在这种情况下,两个活动的每次转化成本相同,但蓝色活动的印象份额可能更高(因为每次点击你支付的费用更多)。重要的是,通常情况下,当你拥有 80%的印象份额时,很难去追求你没有展示广告的额外的潜在客户,而当你的印象份额为 20%时,很难去追求更多的潜在客户,因此(经验法则)印象份额越高,你的每次转化的边际成本就越高,这在印象份额的两个极端都特别明显。下面是一个基于真实生活的例子,展示了印象份额在每次转化的边际成本中的作用:

边际成本和搜索印象份额

例子 2:你的主要竞争对手通过网络和应用程序提供服务,为了吸引客户,他们同时使用谷歌搜索广告和通用应用程序活动。这意味着你的竞争对手在移动设备上比在电脑上争夺相同搜索关键词的可能性更大,概率更高。电脑设备的竞争格局将更加有利,在所有条件相同的情况下,你会预计移动设备的每次转换边际成本将高于电脑。

边际成本和设备类型

潜在对内分泌起重要作用的因素列表:

  • 印象份额(以及竞争力的其他衡量标准,如平均位置、页面绝对顶部等。)
  • 设备
  • 位置
  • 受众(与您的网站有过互动的人与没有向您注册过任何活动的人;性别;人口统计;等等。)
  • 活动类型/广告组类型
  • 关键字匹配类型
  • 一天中的时间和一周中的日期
  • 网络
  • 年龄和性别等人口统计因素
  • 其他人喜欢天气(在上面的例子中提到);重大事件的发生(对于报纸业务);等等。你的创造力能让你得到多少就有多少

最后,关于这些分析最重要的是,它们应该并且很可能会告知您接下来将运行哪些测试。让我们再说一遍,这是您运行的第一个测试,您对哪些因素最有助于客户的增量没有先入为主的想法。在你运行这样的探索性分析后,你将能够制定一个更强有力的假设,并确保你设计一个测试来统计证明(或不证明)这一点。例如,您可以将活动分为四组,因为您观察到一种模式并设计了一个测试,该测试将确保您精确地找到它们的增量水平,并根据测试结果在它们之间转移支出;或者,您可以设计一个测试,以确认(或不确认)印象份额较高的活动/广告组/或设备的增量较小,从而将预算转移到信息系统级别较低的活动/广告组/设备。

7)总结并准备未来的内分泌测试。

如果你已经做到了这一步,那么恭喜你,你做到了——你已经在一个增量框架中优化了你的付费搜索账户。然而,现在也是思考未来的时候了,你将如何在一个渐进的世界中继续运作。下面列出了您在总结阶段需要考虑的 3 件最重要的事情:

  • 我们希望测试结果是决定性的,并导致你采取这样或那样的行动,但即使是这样,这些发现也可能不会持续很久:拍卖的竞争格局是不断演变的,因此每次转换的边际成本将不断变化。你需要做好计划,以便在你的账户中保持一个合理的、恒定的测试水平,这样你就可以有准确的、最新的答案来指导你的优化目标。
  • 您需要决定您将运行的下一组测试是否将在与第一组测试相同的维度上进行(即,按给定逻辑分组的客户/投资组合/活动等)。).如果是这种情况,您仍然需要检查测试设置是否有任何需要更改的地方(您能否在更短的时间内运行它?根据您现在所知道的,您应该改变测试指标吗?等等。).或者,您可能已经在探索性分析中发现了一些有趣的东西,现在想要确认(从统计学角度来说)。例如,在下一个测试中,您可以将您的活动分组为低/中/高印象份额,并测试增加/减少不同组的不同竞价级别;或者,您可能想测试不同的手机/平板电脑/电脑设备乘数,而不是改变活动的出价。
  • 最后,在某些时候,您还会想要考虑在实现和测量这些测试方面的某种自动化。

结论

这篇文章讲述了付费搜索增量背后的原因,为什么你应该在你的营销优化程序中实现它,以及一个实际实现它的方法;但是我不会用这一节来强调任何一点,我会把它留到最后来讨论真正重要的影响。希望这将是额外的动力,你需要实际去做,并在你的付费搜索帐户上实现它。所以,让我以一家我们实施了这种方法的初创公司来结束我的演讲,以及它对公司的意义:

  • 背景:这是一家处于高增长阶段的公司,因此从历史上看,他们愿意在每次转换的成本和每次转换的收入(平均)上达到收支平衡。在某个特定时期,该公司开始感到有必要展示盈利的迹象,这样谷歌广告就不能再以盈亏平衡的成本(平均)运营了。因此,挑战被定义为:从平均收支平衡走向边际收支平衡。
  • 该方法是从投标级别 x 到 y 到 z 进行一系列测试(每个测试都遵循上述 7 个实际步骤),以找到投标级别曲线中每次转换的边际成本与到目前为止的平均成本相同的点。
  • 结果是:1)我们在付费搜索中每节省 10%的总支出,我们只牺牲了付费搜索产生的总转化率的 4.2%。2) 从付费搜索的收支平衡到广告支出的回报率达到 233% 。3)没有单笔转股给公司带来亏损。

其他想法

留下一张便条,说明除了草稿和实验路线之外,解决这一挑战的潜在替代方法。第一个是使用谷歌广告竞价排名——这基本上是谷歌对支出、转换和转换价值的估计,如果你有不同的目标 cpas 或目标 road。您可以在 google ads UI 中一次性使用这些功能,或者通过 API 以编程方式使用这些功能:主要缺点是这些功能只能在广告组级别上使用,可能无法很好地概括您的用例,此外,广告组需要满足某些标准。如果这可以通过活动或组合级别的 API 实现,这将变得非常强大。第二种选择是使用traffic estimator API——我自己还没有使用过,因为我一直在使用智能竞价,但如果你使用手动竞价,这个工具应该可以帮助你计算出不同竞价级别(在这种情况下是最大 cpcs)下你会产生多少点击,如果你假设从点击到转化的转换率相同,你就可以计算出从竞价级别 x 到竞价级别 y 的每次转化的边际成本。

使用(Py)Stan 的应用贝叶斯推理的简单介绍

原文:https://towardsdatascience.com/painless-introduction-to-applied-bayesian-inference-using-py-stan-36b503a4cd80?source=collection_archive---------14-----------------------

贝叶斯回归在 PyStan 中的应用

我们鼓励你在阅读这篇文章之前先看看这个概念背景。

设置

Stan【1】是一个用于贝叶斯推理和模型拟合的计算引擎。它依赖于哈密尔顿蒙特卡罗(HMC) [2]的变体,从大量分布和模型的后验分布中进行采样。

下面是设置 Stan 的详细安装步骤:https://pystan . readthedocs . io/en/latest/installation _ beginner . html

对于 MacOS:

  • 安装miniconda / anaconda
  • 安装xcode
  • 更新你的 C 编译器:conda install clang_osx-64 clangxx_osx-64 -c anaconda
  • 创造环境stanpystan
  • 键入conda install numpy安装 numpy 或用您需要安装的包替换 numpy
  • 安装 pystan: conda install -c conda-forge pystan
  • 或者:pip install pystan
  • 还要安装:arvizmatplotlibpandasscipyseabornstatsmodelspicklescikit-learnnb_condanb_conda_kernels

设置完成后,我们可以打开(Jupyter)笔记本,开始工作。首先,让我们用以下代码导入我们的库:

import pystan
import pickle
import numpy as np
import arviz as az
import pandas as pd
import seaborn as sns
import statsmodels.api as statmod
import matplotlib.pyplot as plt
from IPython.display import Image
from IPython.core.display import HTML

掷硬币推理

回想一下在概念背景中,我是如何谈到在地上找到一枚硬币,并把它扔 K 次以获得公平感的。

我们满足于以下模型:

Y 的概率质量函数(PMF)如下:

首先,通过使用 NumPy 的random功能进行仿真,我们可以了解参数 a=b=5 的先验的行为:

sns.distplot(np.random.beta(5,5, size=10000),kde=False)

正如在概念背景中提到的,这个先验似乎是合理的:它在 0.5 左右是对称的,但在两个方向都有可能出现偏差。然后我们可以用下面的语法在pystan中定义我们的模型:

  • data对应我们模型的数据。在这种情况下,整数N 对应于投掷硬币的次数,而y对应于长度为N的整数向量,它将包含我们实验的观察结果。
  • parameters对应于我们模型的参数,在本例中为theta,或者获得“人头”的概率。
  • model对应于我们的先验(beta)和似然(bernoulli)的定义。
# bernoulli model
model_code = """data {int<lower=0> N;int<lower=0,upper=1> y[N];}parameters {real<lower=0,upper=1> theta;}model {theta ~ beta(5, 5);for (n in 1:N)y[n] ~ bernoulli(theta);}"""data = dict(N=4, y=[0, 0, 0, 0])
model = pystan.StanModel(model_code=model_code)
fit = model.sampling(data=data,iter=4000, chains=4, warmup=1000)la = fit.extract(permuted=True)  # return a dictionary of arraysprint(fit.stansummary())

注意model.sampling的默认参数是iter=1000chains=4warmup=500。我们根据我们的时间和可用的计算资源来调整这些。

  • iter ≥ 1 对应于我们每个 MCMC 链的运行次数(对于大多数应用来说,不应少于 1000 次)
  • warmup或“老化”≥ 0 对应于我们采样开始时的初始运行次数。考虑到这些链在开始运行时非常不稳定和幼稚,实际上我们通常定义这个量来丢弃第一个 B= warmup数量的样本。如果我们不丢弃 B,那么我们就在估计中引入了不必要的噪声。
  • chains ≥ 1 对应于我们采样中的 MCMC 链数。

下面是上述模型的输出:

Inference for Stan model: anon_model_d3835c4370ff5e66f1e88bd3eac647ff.
4 chains, each with iter=4000; warmup=1000; thin=1; 
post-warmup draws per chain=3000, total post-warmup draws=12000. mean se_mean     sd   2.5%    25%    50%    75%  97.5% 
theta   0.36  1.8e-3   0.12   0.14   0.27   0.35   0.44   0.61   
lp__   -9.63  9.3e-3   0.71 -11.63  -9.81  -9.36  -9.18  -9.13 
  • 我们的theta的后验均值大约是0.36 < 0.5。尽管如此,95%的后验可信区间还是相当宽的:(0.14,0.61)。因此,我们可以说这个结果在统计学上不是结论性的,但是它指向偏见,而没有偶然跳到 0。

应用回归:汽车和每加仑英里数(MPG)

图片来自 Pixabay 的苏珊·苏厄特

让我们构建一个贝叶斯线性回归模型来解释和预测不同规格和品牌的汽车数据集中的每加仑英里数(MPG)。尽管我的方法是一种“经典的”基于可能性的方法,或者更确切地说,是一种以分布为中心的方法,但是我们可以(并且应该!)使用原始的 ML 训练测试分割来评估我们预测的质量。

该数据集来自 UCI ML 知识库,包含以下信息:

 1\. mpg: continuous 2\. cylinders: integers3\. displacement: continuous 4\. horsepower: continuous 5\. weight: continuous 6\. acceleration: continuous 7\. model year: integers8\. origin: categorical9\. car name: string (index for each instance)

为什么我们不坚持我们的基本原则,使用标准线性回归?[3]回忆其功能形式如下:

  • y 对应于我们的因变量,或感兴趣的结果—这里是mpg
  • x 是具有 P 个特征或独立变量的 N 个样本的 N×P 矩阵。
  • α是一个 N x 1 向量,表示模型截距,根据您的编码方案,可能有不同的解释。
  • β是回归量/特征系数的 P×1 向量。
  • ε是一个 N×1 随机向量,它遵循一个多变量正态分布,N×N协方差矩阵表示为σ。标准的线性回归情况要求该σ是沿对角线σ >为 0 的对角矩阵,即观测值之间的独立性

现在,对于贝叶斯公式:

虽然前两条线看起来完全一样,但我们现在需要建立α、β和σ的先验分布。

在执行 EDA 时,我们应该始终考虑以下几点:

  • 我的可能性有多大?
  • 我的模型应该是什么?互动 vs 无互动?多项式?
  • 我的参数(和超参数)是什么,我应该选择什么样的先验?
  • 我是否应该考虑任何聚类、时间或空间相关性?

电子设计自动化(Electronic Design Automation)

与任何类型的数据分析一样,至关重要的是首先了解我们感兴趣的变量/特征,以及它们之间以及与我们的 y /结果之间的关系。

让我们从加载数据集开始:

cars_data = pd.read_csv("[~/cars.csv](https://raw.githubusercontent.com/sergiosonline/sergiosonline.github.io/master/files/cars.csv)").set_index("name")
print(cars_data.shape)
cars_data.head()

让我们检查一下目标变量和预测变量之间的关系(如果有的话)。这里origin表示汽车的产地——它有三个等级:“美国”、“日本”和“欧洲”

sns.distplot(cars_data[cars_data['origin']=='American']['mpg'],color="skyblue", label="American",kde=False)
sns.distplot(cars_data[cars_data['origin']=='Japanese']['mpg'],color="red", label="Japanese",kde=False)
sns.distplot(cars_data[cars_data['origin']=='European']['mpg'],color="yellow", label="European",kde=False)
plt.legend()

美国汽车和日本汽车似乎有一些有趣的区别。

现在让我们检查一下数字变量和mpg之间的关系:

  • 我更喜欢将这些可视化,而不是简单地计算相关性,因为这给了我它们之间关系的视觉和数学感觉,超越了简单的标量。
f, axes = plt.subplots(2, 3, figsize=(7, 7), sharex=False)sns.relplot(x="cylinders", y="mpg", data=cars_data, ax=axes[0, 0]);
sns.relplot(x="displacement", y="mpg", data=cars_data, ax=axes[0, 1]);
sns.relplot(x="horsepower", y="mpg", data=cars_data, ax=axes[0, 2]);
sns.relplot(x="acceleration", y="mpg", data=cars_data, ax=axes[1, 0]);
sns.relplot(x="year", y="mpg", data=cars_data, ax=axes[1, 1]);
sns.relplot(x="weight", y="mpg", data=cars_data, ax=axes[1, 2]);# close pesky empty plots
for num in range(2,8):plt.close(num)plt.show()

除了年份加速度之外,其他年份都与 mpg 负相关,即排量每增加 1 个单位,mpg 就会减少。

培训/安装

让我们为拟合和测试准备数据集:

from numpy import random
from sklearn import preprocessing, metrics, linear_model
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_errorrandom.seed(12345)cars_data = cars_data.set_index('name')
y = cars_data['mpg']
X = cars_data.loc[:, cars_data.columns != 'mpg']
X = X.loc[:, X.columns != 'name']
X = pd.get_dummies(X, prefix_sep='_', drop_first=False) 
X = X.drop(columns=["origin_European"]) # This is our reference categoryX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.15, random_state=0)X_train.head()

现在,转到我们的模型规范,它基本上没有偏离上面的抛硬币问题,除了我使用矩阵符号来尽可能简化模型表达式的事实:

# Succinct matrix notationcars_code = """
data {int<lower=1> N; // number of training samplesint<lower=0> K; // number of predictors - 1 (intercept)matrix[N, K] x; // matrix of predictorsvector[N] y_obs; // observed/training mpgint<lower=1> N_new;matrix[N_new, K] x_new;
}
parameters {real alpha;vector[K] beta;real<lower=0> sigma;vector[N_new] y_new;
}
transformed parameters {vector[N] theta;theta = alpha + x * beta;
}
model {sigma ~ exponential(1);alpha ~ normal(0, 6);beta ~ multi_normal(rep_vector(0, K), diag_matrix(rep_vector(1, K)));y_obs ~ normal(theta, sigma);y_new ~ normal(alpha + x_new * beta, sigma); // prediction model
}
"""
  • data对应于我们模型的数据,如上面掷硬币的例子。
  • parameters对应我们模型的参数。
  • transformed parameters这里允许我将theta定义为我们的模型在训练集上的拟合值
  • model对应于我们对sigmaalphabeta的先验的定义,以及我们对 P(Y|X,α,β,σ) ( normal)的似然。

上述先验是在初始数据检查后选择的:

  • 为什么σ是指数先验?嗯,σ ≥ 0(根据定义)。为什么不是制服或者伽玛? PC 框架!【4】——我的目标是最节俭的模式。
  • α 和β呢?这里最简单的事情是,给定一个正态概率,为这些参数选择正态先验是很方便的。您可能希望为这两个参数中的每一个选择不同的超参数。
  • 为什么β是一个multi_normal()?数理统计中有一个众所周知的结果,即长度为< ∞且具有单位对角协方差矩阵和向量均值μ < ∞的多正态随机变量(向量 W)等价于一个服从 N(μ,1)分布的独立正态随机变量 W 的向量。

关于 stan 有趣的是,我们可以请求在测试集上进行预测而无需重新拟合——更确切地说,它们可以在第一次调用中被请求。

  • 我们通过在上面的调用中定义y_new来实现这一点。
  • theta是我们对训练集的拟合预测。

我们指定要摄取的数据集,并继续从模型中取样,同时保存它以供将来参考:

cars_dat = {'N': X_train.shape[0],'N_new': X_test.shape[0],'K': X_train.shape[1],'y_obs': y_train.values.tolist(),'x': np.array(X_train),'x_new': np.array(X_test)}sm = pystan.StanModel(model_code=cars_code)
fit = sm.sampling(data=cars_dat, iter=6000, chains=8)# Save fitted model!
with open('bayes-cars.pkl', 'wb') as f:pickle.dump(sm, f, protocol=pickle.HIGHEST_PROTOCOL)# Extract and print the output of our model
la = fit.extract(permuted=True)
print(fit.stansummary())

以下是我打印的输出(出于本教程的目的,我去掉了Rhatn_eff):

Inference for Stan model: anon_model_3112a6cce1c41eead6e39aa4b53ccc8b.
8 chains, each with iter=6000; warmup=3000; thin=1; 
post-warmup draws per chain=3000, total post-warmup draws=24000.mean se_mean     sd   2.5%    25%    50%    75%  97.5%  
alpha       -8.35    0.02   3.81 -15.79 -10.93  -8.37  -5.74  -0.97  
beta[1]     -0.48  1.9e-3   0.33  -1.12   -0.7  -0.48  -0.26   0.17  
beta[2]      0.02  4.6e-5 7.9e-3 6.1e-3   0.02   0.02   0.03   0.04  
beta[3]     -0.02  8.7e-5   0.01  -0.04  -0.03  -0.02-6.9e-3   0.01  
beta[4]   -7.0e-3  4.0e-6 7.0e-4-8.3e-3-7.4e-3-7.0e-3-6.5e-3-5.6e-3  
beta[5]       0.1  5.9e-4    0.1   -0.1   0.03    0.1   0.17    0.3  
beta[6]      0.69  2.7e-4   0.05    0.6   0.65   0.69   0.72   0.78  
beta[7]     -1.75  2.9e-3   0.51  -2.73  -2.09  -1.75  -1.41  -0.73  
beta[8]      0.36  2.7e-3   0.51  -0.64   0.02   0.36   0.71   1.38  
sigma        3.33  7.6e-4   0.13   3.09   3.24   3.32   3.41   3.59  
y_new[1]    26.13    0.02   3.37  19.59  23.85  26.11  28.39  32.75  
y_new[2]    25.38    0.02   3.36  18.83  23.12  25.37  27.65  31.95
...
...
theta[1]    24.75  2.7e-3   0.47  23.83  24.44  24.75  25.07  25.68  
theta[2]    19.59  2.6e-3   0.43  18.76   19.3  19.59  19.88  20.43 
...
... 

fit.stansummary()是一个像表格一样排列的字符串,它给出了拟合过程中估计的每个参数后验均值、标准差和几个百分点。当alpha对应于截距时,我们有 8 个beta回归量,一个复杂性或观察误差sigma,我们在训练集theta上的拟合值,以及我们在测试集y_new上的预测值。

诊断

在引擎盖下运行 MCMC,我们以图表的形式检查基本诊断是至关重要的。对于这些图,我依靠优秀的arviz库进行贝叶斯可视化(和PyMC3一起工作也一样)。

  • 链式混合 —轨迹图。这些系列图应显示出**“厚毛**”链在真实直线的“合理尺寸”区间内振荡,以指示良好的混合。“稀疏”链意味着 MCMC 没有有效地探索,并且可能在某些异常处停滞不前。
ax = az.plot_trace(fit, var_names=["alpha","beta","sigma"])

粗毛铁链!由于图像大小,我省略了 alpha 和 beta[1:2]。

  • 我们参数的后验可信区间 —森林样地。这些应该作为我们的模型参数(和超参数)的比例和位置的可视化指南!).例如,σ(这里是 PC 框架[4]下的一个复杂度参数)不应该达到< 0。与此同时,如果ϐ预测值的可信区间不包含 0,或者如果 0 几乎不在其中,我们就可以获得“统计显著性”的意义
axes = az.plot_forest(post_data,kind="forestplot",var_names= ["beta","sigma"],combined=True,ridgeplot_overlap=1.5,colors="blue",figsize=(9, 4),
)

看起来不错。**alpha**这里可以看作是代表我们引用类别的“collector”(我用的是引用编码)。我们当然可以规范化我们的变量,以实现更友好的缩放——我鼓励你尝试一下。

预言;预测;预告

贝叶斯推理具有预测能力,我们可以通过从预测后验分布中取样来产生预测能力:

这些(以及整个贝叶斯框架)的伟大之处在于,我们可以使用**(预测)可信区间**来给我们估计的方差/波动性的感觉。毕竟,如果一个预测模型的预测 50 次中有 1 次“足够接近”目标,那么它有什么用呢?

让我们看看我们的预测值与测试集中的观察值相比如何:

dff = pd.DataFrame({'y_pred':la['y_new'].mean(0), 'y_obs':y_test})
grid = sns.JointGrid(dff.y_pred, dff.y_obs, space=0, height=6, ratio=50,xlim=(0,50), ylim=(0,50))
grid.plot_joint(plt.scatter, color="b")
x0, x1 = grid.ax_joint.get_xlim()
y0, y1 = grid.ax_joint.get_ylim()
lims = [max(x0, y0), min(x1, y1)]
grid.ax_joint.plot(lims, lims, ':k')plt.subplots_adjust(top=0.9)
grid.fig.suptitle('Bayes Test Predicted vs Obs',fontsize=20)
plt.show()

直虚线表示完美的预测。我们离它不远了。

然后,我们可以对这些预测进行 ML 标准度量(MSE ),以评估它们相对于保留测试集中的实际值的质量。

bay_test_mse = metrics.mean_squared_error(y_test, la['y_new'].mean(0))
print('Bayes Test MSE:', bay_test_mse)##### Bayes Test MSE: 10.968931376358526

当我们改变一些模型输入时,我们还可以可视化我们预测的值(以及它们相应的 95%可信区间):

az.style.use("arviz-darkgrid")sns.relplot(x="weight", y="mpg")data=pd.DataFrame({'weight':X_test['weight'],'mpg':y_test}))
az.plot_hpd(X_test['weight'], la['y_new'], color="k", plot_kwargs={"ls": "--"})

sns.relplot(x="acceleration", y="mpg",data=pd.DataFrame({'acceleration':X_test['acceleration'],'mpg':y_test}))
az.plot_hpd(X_test['acceleration'], la['y_new'], color="k", plot_kwargs={"ls": "--"})

在下文中,我使用statsmodels比较了我的贝叶斯模型和普通最大似然线性回归模型的性能:

他们表现得非常接近(为了这颗特殊的种子)。

**最佳实践:**为了获得模型性能的“更好”想法,您应该通过运行 K ≥ 30 训练测试分割的实现,在测试 MSE 上引导 95% 置信度区间(CLT)。

这是整个笔记本。py 导出格式:

https://gist . github . com/sergiosonline/6 a3 E0 b 1345 c8 f 002d 0e 7 b 11 AAF 252d 44

考虑

  • 请注意,回归分析是一个现代数据科学问题大家族的一个非常容易的起点。在本教程之后,我希望你开始思考它的两种风格:ML(基于损失)和 classical(基于模型/可能性)。
  • 贝叶斯推理并不难结合到您的 DS 实践中。采用基于损失的方法作为贝叶斯方法是可能的,但这是我将在后面讨论的主题。
  • 只要你知道自己在做什么就有用!事先说明。但是当你没有有限数量的数据(昂贵的数据收集/标记、罕见事件等)或者你确切知道你想要测试或避免什么时,它特别有用。
  • 贝叶斯框架很少在 ML 任务(预测、分类等)中胜过它的(频繁主义者)ML 对应物,特别是当数据集的规模增长时。当处理大型数据集(大数据)时,您的先验知识很容易被数据淹没。
  • 正确指定的贝叶斯模型是一个生成模型,因此您应该能够轻松地生成数据,以检查您的模型与正在讨论的数据集/数据生成过程的一致性。
  • EDA 和 plots 在模型构建和检查过程之前、之中和之后都是至关重要的。[5]是一篇关于贝叶斯工作流中可视化重要性的精彩论文。

进一步的方向

我鼓励你批判性地思考改进这种预测的方法,不仅从贝叶斯的角度,而且从 ML 的角度。

数据集是否足够大或丰富,可以从严格的 ML 方法中受益?有哪些方法可以改进这个贝叶斯模型?在什么情况下,这个模型一定会优于 MLE 模型?如果观察值以某种方式相关(聚集的、自相关的、空间相关的等等)会怎样?当可解释性是建模优先考虑的问题时,该怎么做?

如果你想知道如何将贝叶斯方法扩展到深度学习,你也可以研究一下变分推理 [6]方法,作为纯贝叶斯治疗的可扩展替代方案。这里的是“简单”的概述,这里的是技术回顾。

参考文献

1 B. Carpenter 等人 Stan:一种概率编程语言 (2017)。统计软件杂志 76 卷 1 期。DOI 10.18637/jss.v076.i01。

[2]贝当古先生。哈密顿蒙特卡罗概念介绍 (2017)。arXiv:1701.02434

[3] J .韦克菲尔德。贝叶斯和频率主义回归方法 (2013)。统计学中的斯普林格级数。斯普林格纽约。doi:10.1007/978–1–4419–0925–1。

[4] D. Simpson 等人惩罚模型组件复杂性:构建先验的原则性实用方法 (2017)。摘自:统计科学 32.1,第 1-28 页。doi: 10.1214/16-STS576。

[5] J. Gabry 等贝叶斯工作流中的可视化 (2019)。J. R. Stat。社会主义者答:182:389–402。doi:10.1111/rssa.12378

[6] D.M. Blei et al. 变分推断:统计学家综述 (2016)。美国统计协会杂志,第 112 卷,Iss。518,2017 年 DOI:10.1080/01621459 . 5565656567

用 Python 中的 OpenCV 进行绘画和素描

原文:https://towardsdatascience.com/painting-and-sketching-with-opencv-in-python-4293026d78b?source=collection_archive---------20-----------------------

制作油画和水彩画之类的艺术,画素描,用 Python 中的 OpenCV 创作点彩艺术。

由乔丹娜·科德罗在 Unsplash 上拍摄的照片

OpenCV 是一个强大的计算机视觉库,具有强大的图像处理工具包。在本文中,我们将利用它来创建绘图和绘画,其中大多数将使用内置函数!让我们简短地介绍一下,直接进入激动人心的部分。

目录

  • 要求
  • 油画效果
  • 水彩效果
  • 黑白和彩色铅笔素描
  • 点彩艺术

要求

油画效果需要 OpenCV Contrib 模块,而其他效果可以使用 OpenCV 的标准发行版来实现。除此之外,点彩艺术需要 Sklearn 和 Scipy。

pip install opencv-contrib-python==4.3.0.36
pip install scikit-learn
pip install scipy

油画效果

它包含在cv2.xphoto()中,它还具有其他几个很酷的功能,如图像修复、白平衡、图像去噪等。

import cv2img = cv2.imread('img.jpg')
res = cv2.xphoto.oilPainting(img, 7, 1)

原象

油画效果

水彩效果

像油画效果一样,水彩效果也可以用一行代码完成,不包括导入和图像读取。由cv2.stylization()完成。

import cv2img = cv2.imread('img.jpg')
res = cv2.stylization(img, sigma_s=60, sigma_r=0.6)# sigma_s controls the size of the neighborhood. Range 1 - 200# sigma_r controls the how dissimilar colors within the neighborhood will be averaged. A larger sigma_r results in large regions of constant color. Range 0 - 1

水彩效果

黑白和彩色铅笔素描

同样,只需要一行代码,我们就可以得到灰度和彩色的草图。

import cv2 img = cv2.imread('img.jpg')
dst_gray, dst_color = cv2.pencilSketch(img, sigma_s=60, sigma_r=0.07, shade_factor=0.05) # sigma_s and sigma_r are the same as in stylization.# shade_factor is a simple scaling of the output image intensity. The higher the value, the brighter is the result. Range 0 - 0.1

黑白素描

彩色素描

点彩艺术

根据维基百科,点彩艺术可以定义为:

点彩是一种绘画技巧,在这种技巧中,小的、不同的颜色点被应用到图案中以形成图像

要在 Python 中做到这一点,我们的第一步是计算使用 Kmeans 最多的颜色。我使用了 20 的调色板,这意味着点将由 20 个最常用的颜色在图像中出现。根据图像尺寸为点计算合适的半径尺寸。然后我们在图像上循环,找到最接近圆点的颜色,用它来画圆。

import scipy.spatial
import numpy as np
import random
import cv2
import math
from sklearn.cluster import KMeansdef compute_color_probabilities(pixels, palette):distances = scipy.spatial.distance.cdist(pixels, palette)maxima = np.amax(distances, axis=1)distances = maxima[:, None] - distancessumm = np.sum(distances, 1)distances /= summ[:, None]return distancesdef get_color_from_prob(probabilities, palette):probs = np.argsort(probabilities)i = probs[-1]return palette[i]def randomized_grid(h, w, scale):assert (scale > 0)r = scale//2 grid = []for i in range(0, h, scale):for j in range(0, w, scale):y = random.randint(-r, r) + ix = random.randint(-r, r) + j grid.append((y % h, x % w)) random.shuffle(grid)return griddef get_color_palette(img, n=20): clt = KMeans(n_clusters=n)clt.fit(img.reshape(-1, 3))return clt.cluster_centers_def complement(colors):return 255 - colorsdef create_pointillism_art(image_path, primary_colors):img = cv2.imread(image_path)radius_width = int(math.ceil(max(img.shape) / 1000))palette = get_color_palette(img, primary_colors)complements = complement(palette)palette = np.vstack((palette, complements))canvas = img.copy() grid = randomized_grid(img.shape[0], img.shape[1], scale=3)pixel_colors = np.array([img[x[0], x[1]] for x in grid])color_probabilities = compute_color_probabilities(pixel_colors, palette)for i, (y, x) in enumerate(grid):color = get_color_from_prob(color_probabilities[i], palette)cv2.ellipse(canvas, (x, y), (radius_width, radius_width), 0, 0, 360, color, -1, cv2.LINE_AA) return canvasres = create_pointillism_art('img.jpg', 20)

原象

结果

点彩艺术的代码受到这个 GitHub 库的启发,做了一些修改。

所以我们看到用 OpenCV 制作艺术是小菜一碟,尤其是使用内置函数。如果你想看到使用 OpenCV 的图像编辑操作,你可以参考这篇文章:

[## 使用 OpenCV 设计图像滤镜(第 1 部分)

我们都编辑过我们的图像,也许是为了改善白平衡,增加温暖,使用不同的滤镜,甚至…

medium.com](https://medium.com/dataseries/designing-image-filters-using-opencv-like-abode-photoshop-express-part-1-8765e3f4495b)

用机器学习绘制像素艺术

原文:https://towardsdatascience.com/painting-pixel-art-with-machine-learning-5d21b260486?source=collection_archive---------5-----------------------

使用 GANs 帮助真正的艺术家更快地完成游戏

雪碧生产流水线的几个阶段。即草图、艺术线条、阴影、区域和索引。

上面的精灵来自 Trajes Fatais: Suits of Fate 游戏,我是这个游戏的首席开发者。长话短说,每个精灵需要大约一个小时来绘制,每个角色平均需要五百个精灵。在“面向游戏的机器学习辅助资产生成:像素艺术精灵表的研究”中,我们探索了 Pix2Pix 架构来自动化精灵生产流水线,将每个精灵花费的平均时间减少了 15 分钟(~25%)。这是我们第一个发表的关于精灵生成的工作,我们期望在未来进一步改进它。

这篇论文获得了 2019 年巴西游戏数字娱乐研讨会(SBGames 2019)颁发的最佳论文奖

P 像素艺术是电子游戏中最流行的美学之一。它努力重现旧任天堂和街机游戏的外观和感觉。在 90 年代,像素艺术是大多数游戏机的唯一选择。屏幕分辨率有限,大多数设备无法实时执行高级技术。今天,像素艺术是一种选择——一种昂贵的选择。

为了实现街机游戏的外观和感觉,艺术家必须接受时代的限制。最初的游戏机只有四种绿色。它的继任者 Game Boy Color 可以同时显示多达 56 种不同的颜色。后来的设备,被称为 16 位一代,允许每个字符多达 256 种颜色,这是美学上的一个重大变化。在我们的游戏中,我们把自己限制在每个角色 256 种颜色的范围内。

每个角色和背景都有自己的 256 种颜色

通常,角色是“索引精灵”和“调色板”的混合绘画时,艺术家用与调色板中 256 种颜色之一相关的“索引”来给每个像素着色。在游戏中,每个索引精灵都被替换为其相关的颜色,组成最终的图像。这个过程允许设计者为每个角色创建不同的“皮肤”,允许用户定制他们的体验,并为角色创建“邪恶”版本。下图描述了索引精灵、调色板和渲染混合。

索引精灵、调色板和最终渲染

将艺术家限制在 256 色是不自然的。选择色调是困难的。为了简化这项任务,工作在语义上进行了划分。在我们的管道中,生成了两个中间精灵:“着色”和“区域”精灵。前者最多使用 6 个色调,表示“光”,后者最多使用 42 个色调,表示精灵的“区域”,如手臂、头发、腿等。将两个精灵按像素相乘,我们得到了索引精灵,它允许多达 252 种颜色(6 * 42)。下图显示了着色、区域和索引精灵的示例。这个过程将 256 色问题转化为两个简单的子问题,每个子问题有 6 色和 42 色。

从左到右,着色,区域和索引精灵。

最后,每个角色都是由一个人设计的,这就产生了所有动画的概念艺术。这些被呈现在一个“素描”精灵中,然后被精炼成一个“艺术线条”精灵。前者用于快速制作游戏中新动画的原型,后者用于与其他艺术家交流最终的精灵应该是什么样子。这样,设计师可以在几天内构思出一个完整的角色,然后将剩余的工作外包给绘图团队。以下是素描和艺术线条精灵的示例:

素描和艺术线条精灵

将所有这些放在一起,设计师通过绘制每个动画来创建角色,然后制作他们各自的艺术线条。接下来,这些艺术线条精灵被交给绘图团队,他们将绘制各自的着色和区域精灵。最后,一个脚本将两者结合起来,生成游戏就绪的索引精灵。

总的来说,这个过程需要大约一个小时。草图、艺术线条和区域精灵的制作平均需要 10 分钟,而着色需要一个小时的剩余时间来完成。跟踪每幅画花费的确切时间几乎是不可能的。为了计算它们,我们检查了我们的生产日志,采访了团队,并以可控的方式测量了十几个精灵的步骤。

他的工作假设使用现代生成模型来产生阴影和颜色精灵是可行的。要被认为是有用的,生成的精灵必须足够好,人类艺术家可以在比从头开始更短的时间内完善它。

生成性对抗网络入门

在这项工作中,我们解决了两个图像映射问题:艺术线条到阴影和艺术线条到区域。形式上,我们必须创建一个生成器 G(x ),它从艺术线条域接收输入,并在阴影/区域域产生输出。这个问题也被称为图像翻译。

为了保证 G(x)是一个有用的映射,我们将创建一个鉴别器 D(x,y ),它查看 x 和 y 并判断 y 是否是一个高质量的精灵。换句话说,G 是我们的“虚拟艺术家”,D 是我们的虚拟“质量控制”如果我们能让 G 让 D 开心,我们就有了一个有用的映射。

更详细地说,考虑我们有几个艺术线条精灵(x)和已经绘制的阴影和区域精灵(y),由人类艺术家制作。我们知道这些通过了质量控制,所以 D(x,y)会很高兴。我们现在的任务是训练 g,给定 x,产生ŷ(对真实 y 的模仿)。如果复制良好,d 会批准ŷ;否则,它会责备它。最后,我们剧透 D 是对是错,我们请它给 g 建设性的反馈。

我刚才描述的程序被称为对抗性训练。两个模型在某种意义上“竞争”,一个试图击败另一个。在我们的例子中,g 试图击败 d,让他认为ŷ是 y,而 d 拼命地分辨什么是真的,什么是假的。随着时间的推移,G 会成为一个成功的艺术家😄和 D 可能会被质量控制部门解雇💩。

通过使用神经网络来实现 G 和 D,我们得到了所谓的条件生成对抗网络。打破标题,“有条件”是因为 G 将 x 作为输入而不是随机噪声,“生成对抗性”是因为它训练对手成为声音生成器,“网络”是因为它是(惊喜!)一个神经网络。

在算法上,对于每个艺术线条 x 和阴影/区域子画面 y:

  1. 使用 g,从 x 生成ŷ
  2. 使用 d,评估ŷ看起来是否真实
  3. 用 y 和 D 的反馈训练 G
  4. 训练 d 认识到ŷ是假的,y 是真的

对整个数据集重复这一过程多次,最终将汇聚成一个 G 网络,创建看起来逼真的精灵和一个 D 网络,无法分辨哪些图像是真的还是假的。

Pix2Pix 架构

Pix2Pix 架构基于 U-Net 生成器和基于补丁的鉴别器。组合架构如下图所示。鉴别器被训练以将ŷ的每个 32×32 的小块分类为真或假,并且用二进制交叉熵损失来训练。反过来,发生器被训练以最小化 y 和ŷ之间的 L1 损耗,并最大化鉴频器损耗。

高级 Pix2Pix 架构。

U-Net 模型是基于编码器-解码器思想的完全卷积神经网络。对于每个编码器层,跳过连接被添加到等效的解码器层。这允许网络利用来自编码层的“原始”信息和通过解码器层的“处理”信息。此处给出了该架构及其相关出版物的全面概述。

基于块的鉴别器是一个截断的网络,输出对几个图像块的判断,而不是对整个图像的单个判断。因此,鉴别器向生成器提供详细的反馈,指出哪些区域看起来真实,哪些看起来虚假。在这里可以找到该建筑内部细节的完整概述。

与原始网络相比,我们进行了以下更改:

  1. 我们使用了一个 Y 形网络。一个编码器、两个解码器和两个鉴别器。这样,着色和区域问题在一次处理中就解决了。
  2. 对于分叉架构,每个分支有两个损耗。此外,我们使用 L2 规范,而不是 L1,因为它显示了更好的结果。
  3. 原纸使用 LeakyReLU 单位。我们使用了 ELU 单位。
  4. 在编码器中,我们对每个下采样步骤使用两次卷积运算,而不是一次卷积。

数据集

从 Trajes Fatais 游戏中,我们选择了 Sarah 和 Lucy 角色作为数据集来评估 Pix2Pix 架构的有用性。莎拉这个角色只有 87 个完成的精灵,还有 207 个有待绘制。它也是一个中等复杂的角色,有几个平滑和复杂的区域。另一方面,Lucy 已经完成了,所以它有 530 个完全绘制的精灵,并且非常容易绘制,具有大部分平滑的特征。

从某种意义上说,露西是我们的上限。它拥有我们所希望的所有数据,并且是一个容易画出的角色。如果算法不能处理 Lucy,那么它很可能对任何其他角色都失败。相比之下,莎拉是我们的理想场景:一个中等复杂的人物,只有几十个精灵准备接受训练。如果它对莎拉有用,那么它可能对我们有生产价值。

结果

可以看出,该算法对于阴影问题和区域精灵问题有很好的效果。也就是说,颜色发生了变化,女孩周围有一点噪声。对于着色精灵,只能检测到小问题,例如第二行中的肩膀和腿。

在第二批中,可以发现更多的问题。在生成的阴影列中,可以在阴影区域中看到许多伪影,例如在女孩(第一行)、鸭嘴兽背部(第二行)和鸭嘴兽喙(第三行)上。对于彩色精灵,存在大量的噪声,使得这些精灵不可用,因为人类很难手工修复噪声。

这第三批来自 207 个精灵,只有艺术线条可用。因此,这些需要主观分析。这些行分别由与训练中使用的精灵相似的精灵、具有以前未见过的姿势的精灵和具有完全不同的姿势的精灵组成。

虽然第一行是最有用的,但第二行和第三行的颜色精灵会很快退化。着色精灵的质量大多是一致的。然而,第三列的着色精灵显示它并不总是一致的。第二排的正面精灵应该有更亮的脸,而它正下方的精灵有不相干的灯光。

现在,我们可以安全地假设着色精灵是有用的,但是区域精灵没有用,因为它们太吵而且有颜色偏移问题。让我们把注意力转移到露西身上。

Lucy sprites 的数据是 Sarah 的五倍,显示出显著的改进。阴影精灵接近完美,只有阴影区域的小问题和头发的可容忍差异。然而,区域精灵还远未达到最佳状态。色偏问题和噪声仍然相关。这表明,增加数据集大小并没有在这些问题上有实质性的改善。

这第二批有我们手动选择在验证集中的精灵,因为它们与大多数其他精灵有很大的不同。尽管如此,着色精灵仍然与他们的人类绘制的对应物几乎相同。至于彩色图像,质量并没有下降太多,就像 Sarah 的情况一样。然而,这还远远不够理想。

考虑到这些结果,可以说增加数据集大小会显著改善阴影,但不会改善区域。因为 Lucy 是我们最好的情况,所以可以安全地假设我们需要另一个问题公式/架构来解决区域精灵问题。

为了更客观地量化生成内容的质量,我们计算了两个数据集的 MSE 、 MAE 和 SSIM 分数。

从表中可以看出,灰色精灵在所有三个指标上都比彩色精灵有更好的均值(μ)和方差(σ)。此外,75%四分位数和最大可见值之间的差异非常大,这表明分布高度偏斜。

此外,Lucy 的结果始终比 Sarah 的好,方差低得多,偏差也小得多。

SSIM 分数范围从 0(完全不相似)到 1(完全相同),测量两幅图像的相似度。虽然 MSE 和 MAE 是纯粹的数学概念,但 SSIM 分数试图与人类感知更相关。在表格中,灰色精灵有接近 1 的分数,这表明它们与普通观察者几乎相同,而彩色精灵则不是这样。

作为第三次也是最后一次评估,我们要求设计团队对为莎拉角色生成的 207 个精灵进行评论。他们的反馈大多是积极的,赞扬了着色精灵的质量,并放弃了彩色精灵。总而言之,他们提出了四点意见:

  1. 几乎一半的阴影精灵是有用的,可以在 20 到 30 分钟内完善。颜色精灵不可用。
  2. 该算法在单个动画中是不一致的,这可能会使精灵的有用性无效。
  3. 一些姿势有可怕的结果,甚至对于着色精灵也是如此。
  4. 当将颜色量化为所使用的 6 和 42 色调时,会引入一些不想要的噪声。

下图说明了第 2、3 和 4 点。

八帧动画中不一致的身体照明

与训练中使用的姿势相差太大的姿势效果不好。

当量化到 6 和 42 音调时,会引入一些噪声。这在等高线上很容易看出来。

讨论

在这项工作中,我们评估了使用现代生成模型来解决像素艺术生成问题。也就是说,我们采用了修改过的 Pix2Pix 架构,取得了一定的成功。更详细地说,着色精灵被艺术团队认为是有用的,而彩色精灵因为无用而被丢弃。

对于公认的阴影精灵,团队规定平均需要 20 到 30 分钟来完善每一个,这比从头画一个要少 10 到 30 分钟。保守估计,每一个有用的精灵将节省 10 分钟的劳动,这意味着大约 15%以上的生产力。

尽管区域精灵有更多的颜色,但对于设计团队来说,它并不像着色精灵那样花费太多的时间。正如首席艺术家所解释的,动画中的区域更容易预测,并且可以很容易地从一个精灵复制到另一个精灵。因此,不生成它们并不是一个大问题。

从技术角度来看,这项工作证明了当前的模型可以有效地用作创造性任务的助手。其他作品也在动漫领域中发现了类似的结论,该领域主要由平坦而充足的表面组成,比像素艺术的限制更少。此外,Pix2Pix 模型是为现实世界的图片而概念化的,但也适用于像素艺术和动漫数据,这证明了它的通用性。

未来的工作

我们当前的系统是基于像素回归的,如 Pix2Pix 模型。然而,我们的问题可以公式化为每像素分类,依赖于图像分割文献。这可能会大大改善我们的结果。

有时,简化问题可能会使它更容易处理。区域精灵总共有 42 种颜色,但是只有十几种出现在每个精灵上,并且占据了很大一部分。将问题缩小到一组更具选择性的色调可能会减轻我们生成器的工作。

Pix2Pix 是 2017 年的。自那以后,GAN 文献取得了一些进展,包括更好的损失函数、注意机制和改进的公式。使用更现代的技术可能会大大改善所获得的结果。

U-Net 和 Pix2Pix 参考

O.Ronneberger,P. Fischer 和 T. Brox,“U-net:生物医学图像分割的卷积网络” 2016

页(page 的缩写)伊索拉,朱,周,埃夫罗斯,“有条件对抗网络的图像到图像翻译” 2017

如果你喜欢这篇评论,你可能会喜欢我在 Medium 上发表的其他文章。这里有一些建议:

  • 撰写科技论文的 10 个技巧
  • 2020 年要读的 AI 论文
  • 所有数据科学家都应该掌握的五项基本技能
  • 激活功能综合指南

欢迎评论或联系我。如果你刚接触媒体,我强烈推荐订阅。对于数据和 IT 专业人士来说,中型文章是 StackOverflow 的完美搭档,对于新手来说更是如此。注册时请考虑使用我的会员链接。

感谢阅读:)

Quantopian 上的 Pairs 校验实现

原文:https://towardsdatascience.com/pairs-check-implementation-on-quantopian-3b10f4e06a34?source=collection_archive---------30-----------------------

两种证券的协整研究及配对检验交易策略的实施。

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

算法交易包括使用交易指令自动执行股票市场中的订单。这些指令是设计用于检测模式并将其用作执行操作的触发器的程序。这种技术利用了计算机相对于人类交易者的速度和情感。

这篇文章展示了如何在 Quantopian 上实现一个叫做 Pairs Check 的算法交易策略。

为了实现这一目标,我们将这篇文章分成 5 个部分:

  1. 结对检查,效果如何?
  2. 分析股票对:CNQ 和 PXD
  3. quanto pian 上的代码实现
  4. 回溯测试策略
  5. 结论

配对检查,它是如何工作的?

配对交易是一种独立于市场条件(上升趋势、下降趋势或横向运动)的市场交易策略,几乎在任何情况下都可以获得正回报。这种策略被归类为统计套利和集中交易策略。它的算法实现允许交易者在人类交易者有机会调整市场之前利用市场的低效率。

Pairs Check 监控两种历史上共同整合的证券的价差。协整背后的直觉可以用一个人遛狗的类比来说明。它们一起移动,它们之间的距离受到皮带长度的限制。在行走过程中,皮带会拉伸和放松,但大多数时候距离在这两个极端之间。

当两只股票之间的价差暂时增大时,例如一只股票上涨,而另一只股票下跌,配对交易将是做空表现出色的股票,做多表现不佳的股票,押注价格差异将会收敛。

两种证券之间的正常差价。

在上图中,我们可以看到两个共同整合证券之间的标准化利差。每当当前价差高于 1.2 或低于-1.2 时,算法就会下单做空价格过高的股票,做多价格过低的股票。

分析股票对:CNQ 和 PXD

在我们的案例研究中,我们将分析 CNQ(加拿大自然资源公司)和 PXD(先锋自然资源公司)之间的关系。我们将使用stats models . TSA . stat tools中的 coint 函数来测试协同集成。

我们将使用的软件包有:

import statsmodels.tsa.stattools as sts
import pandas as pd
import numpy as np
import yfinance
import matplotlib.pyplot as plt

然后导入数据:

*# importing data*
co1 = 'CNQ'
co2 = 'PXD'
tickers = co1 + " " + co2
raw_data = yfinance.download (tickers = tickers, interval = '1d', group_by = 'ticker',auto_adjust = **True**, treads = **True**)

并为分析做准备:

*# defining interval for analysis*
start = '2014-01-01'
end = '2016-06-01'cnq = pd.DataFrame(raw_data[co1][start:end].Close)
pxd = pd.DataFrame(raw_data[co2][start:end].Close)*# filling data gaps*
cnq = cnq.fillna(method = 'bfill')
pxd = pxd.fillna(method = 'bfill')*# renaming columns*
cnq = cnq.rename(columns = {'Close': 'CNQ'})
pxd = pxd.rename(columns = {'Close': 'PXD'})*# normalizing data*
cnq = cnq.apply(**lambda** x: (x-x.min())/(x.max()-x.min()))
pxd = pxd.apply(**lambda** x: (x-x.min())/(x.max()-x.min()))*# charting prices*
chart = pd.concat([cnq, pxd], axis = 1)
chart['CNQ'].plot(figsize = (20,8), color = 'blue')
chart['PXD'].plot()
plt.title('CNQ vs PXD closing prices', size = 24)
plt.legend()
plt.plot()

股票对的标准化价格

最后,我们运行协整检验:

*# co-integration test*
sts.coint(cnq, pxd)

coint 测试中的零假设是两个时间序列没有协整。

因此,从 2014 年到 2016 年,CNQ 和 PDX 高度协整,p 值为 0.0012,这使得这对夫妇成为我们算法的完美候选人。

量子乌托邦上的代码实现

下面的代码是在 Quantopian IDE 上实现的。时间表功能每天在市场关闭前 60 分钟运行程序。阈值根据经验定义为+-1.2。改变这些值可以改变策略的回报。

import numpy as npdef initialize(context):schedule_function(check_pairs, date_rules.every_day(), time_rules.market_close(minutes=60))# Canadian Natural Resourcescontext.cnq = sid(21735)# Pioneer Natural Resources Companycontext.pxd = sid(17436)context.long_on_spread = Falsecontext.shorting_spread = Falsedef check_pairs(context, data):cnq = context.cnqpxd = context.pxdprices = data.history([cnq, pxd], 'price', 30, '1d')short_prices = prices.iloc[-1:]# Spreadmavg_30 = np.mean(prices[cnq] - prices[pxd])std_30 = np.std(prices[cnq] - prices[pxd])mavg_1 = np.mean(short_prices[cnq] - short_prices[pxd])if std_30 > 0:zscore = (mavg_1 - mavg_30) / std_30# Spread = CNQ - PXDif zscore > 1.2 and not context.shorting_spread:order_target_percent(cnq, -0.5) order_target_percent(pxd, 0.5) context.shorting_spread = Truecontext.long_on_spread = Falseelif zscore < 1.2 and not context.long_on_spread:order_target_percent(cnq, 0.5) order_target_percent(pxd, -0.5) context.shorting_spread = Falsecontext.long_on_spread = Trueelif abs(zscore) < 0.1:order_target_percent(cnq, 0)order_target_percent(pxd, 0)context.shorting_spread = Falsecontext.long_on_spread = Falserecord(Z_score = zscore)

回溯测试策略

下面我们可以看到配对检查策略的回溯测试结果。

回报明显好于 SPY 基准,但夏普比率和提款可能会有所改善。

结论

如果这么简单,为什么不是每个人都用支票赚钱呢?嗯,共同整合的股票是独角兽,找到它们并不是一件容易的事情。除此之外,两种证券之间的共同整合可能会随着时间的推移而发生变化,原因有几个:管理和监管变化、客户基础多样化、新技术…

回溯测试结果显示了优于 SPY 基准的回报,但是夏普比率和提取可以改进。

我希望你喜欢这篇文章,我很想听听你关于如何改进这段代码的想法。

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

成对交易 ADR 和间谍

原文:https://towardsdatascience.com/pairs-trading-adr-and-spy-b460c498025b?source=collection_archive---------33-----------------------

算法交易

ADR 价格动态推动交易策略

看着同一个方向?由 SK Yeong 在 Unsplash 上拍摄的照片

美国存托凭证

在美国交易所上市的外国公司股票通常被注册为美国存托凭证。这些是以美元计价的凭证,代表非美国公司证券的股份。约有 2000 种美国存托凭证在纽约证交所和纳斯达克交易,或通过场外交易市场交易,代表着至少 70 个不同国家的公司股票。

美国存托凭证是投资外国公司最直接和最受欢迎的金融工具之一,并被积极用于投资组合的多样化。2015 年,通过美国存托凭证和本地股票持有的外国股票占美国投资者股票投资组合的 19%。

具体而言,根据 JP 摩根的报告,全球对美国和非美国存托凭证的投资总额估计约为 1 万亿美元,其中约 90%投资于美国存托凭证。一些交易量最大的 ETF 也包含美国存托凭证。例如,2015 年末,14 只中国 ADR 被纳入 MSCI 新兴市场指数。跟踪这一指数的 iShares MSCI 新兴市场 ETF (EEM)市值为 240 亿美元,日均成交量为 7200 万股。

在美国交易所交易的亚洲 ADR 的例子。

由于其跨境性质,美国存托凭证的回报在很大程度上取决于美国和原产国市场的市场情绪。特别是,来自亚洲的ADR,如日本、中国香港、中国台湾、印度和韩国,尤其令人感兴趣。

这些美国存托凭证为美国投资者提供了投资外国和新兴市场的直接可行手段。因此,在非亚洲交易所上市的亚洲存托凭证占存托凭证总市值的 44%以上。

不重叠的时区

上述国家的时区比纽约东部标准时间(EST)早 12-14 小时。因此,美国市场和他们本国市场的交易时间并不重叠。原始国内市场在美国市场收盘后开盘,反之亦然。

这导致 ADR 回报相对于其标的股票(在其本国)的不同步 。多资产投资者和其他机构投资者对完全异步的市场特别感兴趣。

类似地,时区差异允许我们将他们的回报分为日内和隔夜两部分,每一部分都有根本不同的价格驱动因素。对于本文研究的美国存托凭证,日内回报可以直观地归因于美国市场的新闻、条件和前景,而隔夜回报主要由当地亚洲市场驱动。在这里,每个市场的波动性贡献是令人感兴趣的。

回报率:隔夜与当天

我们根据由下式定义的平方回报率来比较隔夜回报率的每日比例

每天 i. 一般来说,对于大多数 ADR,该比率的平均值高于 0.5,但对于 SPY,该比率远低于 0.5。较高的比率意味着隔夜回报率比日内回报率有更多的变化。

收益率平方的分布*在区间[0,1]上通常是 u 形的,但不一定是对称的。*对于 SHG 和 LFC 而言,右侧能见度更高。

在 Kang 和 Leung (2016) 中,我们展示了美国存托凭证的其他显著特征,包括日内回报和隔夜回报的关键统计数据、它们的分布以及与美国市场的相关性。

分位数-LFC(左)和 SKM(右)的每日隔夜和当天回报率的分位数图。对于每个图表,x 轴表示标准正态分布的理论分位数,y 轴表示数据真实分布的分位数。十字越靠近直线参考线,经验分布越正常。

2004 年 6 月 15 日至 2014 年 6 月 13 日 ADR 和 SPY 回报统计。每个时间成分的第一列报告 ADR 和 SPY 回报之间的相关系数。第二列报告了平均回报差价(ADR-SPY)。第三列报告回报差价的标准差。对于大多数美国存托凭证来说,日内回报往往与 SPY 有更高的相关性。

每个美国存托凭证与美国市场的相关性是有用的,因为它可以作为一些交易策略的基础。由于盘中回报反映了美国市场时段的价格波动,因此预计它们与美国市场回报的相关性相对较高。同样,隔夜回报率的相关性预计会显著降低。该研究确定了这些相关性,定量对比了它们对各种 ADR 的整体波动性和表现的影响。

均值回复传播

通过 SPDR S&P500 交易所交易基金(SPY)交易的 S&P500 指数和每个美国存托凭证之间的收益率差被发现是一个均值回复时间序列,并通过最大似然估计(MLE)拟合到奥恩斯坦-乌伦贝克过程。

我们用随机微分方程描述的奥恩斯坦-乌伦贝克过程来模拟收益率差

然后,给定在时间 i-1 的先前数据,我们可以将在时间步长 i 的扩散的条件概率表示为

对序列(x(1),x(2),)的一个观察。。。x(N))允许我们计算,从而最大化平均对数似然,定义如下

隔夜、日内和每日收益价差的时间序列:CHL-SPY(左)和 SKM-SPY(右)。

价差交易

为了利用均值回复 ADR-SPY 价差,引入了成对交易策略(ADR 中的多头头寸和 SPY 中的空头头寸)并进行了回溯测试。

在我们的配对交易策略中,我们多头 ADR空头 SPY 。我们选择 SPY 做空,因为它的流动性明显高于 ADR,而且更容易借入。

为了获得最佳结果,我们设置了一个特定的进场水平阈值,并在收益率差 ADR-SPY 低于该阈值 k %时进场。

我们在这里假设多头和空头头寸都值 100 美元,因此净现金流出为零。因此,我们报告的回报不是百分比,而是其支付的现金价值。我们通过将进场门槛从 0%变为-1.5%,步长为-0.5%,平仓天数从 1 天变为 5 天来检验 pairs 交易策略。

基于 2004 年 6 月 15 日至 2014 年 6 月 13 日的经验数据,对(a) CHL 和(b) ASX,在不同的进入阈值(k%)下,均值回复交易策略的平均收益与风险(标准差)的比较。

这篇论文的 pdf 格式如下:https://ssrn.com/abstract=2858048

参考

Kang,J. 和 Leung,T. (2017),异步美国存托凭证:隔夜与日内收益与交易策略《经济与金融研究》,第 34 卷第 4 期,第 580-596 页。https://doi.org/10.1108/SEF-10-2016-0254

Leung T .和 Li X. (2016),最优均值回归交易:数学分析和实际应用,世界科学出版公司(2016)

谷歌学术 // 领英页面 // 主页

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指南 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

用优化的头寸和退出规则进行配对交易

原文:https://towardsdatascience.com/pairs-trading-with-optimized-positions-exit-rules-811fa0c6be91?source=collection_archive---------16-----------------------

算法交易

真实示例、性能总结和 python 包

强大的一对,准备突袭。Geran de Klerk 在 Unsplash 上拍摄的照片。

配对交易是许多市场中最受欢迎的交易策略之一,从股票和 ETF 到货币和期货市场。它包括同时持有两种相关资产的头寸。这个想法是,虽然通常很难准确捕捉单个资产的价格演变,但一对头寸可能表现出均值回归,可以更好地建模。简而言之,pairs trading 是一种市场中性策略,旨在从两种资产的价格趋同中获利。

均值回复价差的实际例子包括股票/交易所交易基金对、期货及其现货、实物商品和相关交易所交易基金等。也有自动识别均值回复投资组合的方法。

配对示例

下面是一些基于市场观察和直觉的资产对的例子。表 1 显示了股票代码和相关交易所交易时间的描述。

美元兑日元:这种选择是由这两种资产之间的正相关性决定的。鉴于日本是出口驱动型的,当日元对美元走强(即美元对日元走弱)时,日经指数预计会因消费下降而下跌。相反,当被视为风险情绪指标的日经指数走软时,日元走强,因此美元兑日元走弱。

USDCAD / CL :加拿大是世界第七大石油生产国。2 这表明石油价格和加元之间存在正相关关系。当原油期货价格上涨时,加元升值,因此美元兑加元下降。

CL / USO : USO 是最大的原油 ETF,由不同到期日的西德克萨斯中质油(WTI)期货组成。因此,普遍服务义务和原油期货价格有望保持一致的正相关关系。

**GC / SI 😗* 在黄金现货和白银现货之间配对交易,同时对金属敞口保持中立。

**AUDJPY / SPX 😗* 这是风险货币 AUDJPY 和股票 S & P500 期货之间的成对交易。后者通常被视为投资者总体风险偏好的晴雨表。

**USDCHF / GC 😗* 瑞士国家银行用黄金来支撑他们持有的一部分瑞士法郎,从而表明这两种资产之间的相关性。当黄金价值增加时,瑞士法郎预计会走强(即美元兑瑞士法郎走弱),反之亦然。

**C / GS 😗* 花旗和高盛是银行业中的两只大盘股。

**AAPL / FB 😗* 苹果和脸书是科技板块的两只大盘股。

资产列表及其股票代码、说明和交易时间(东部标准时间)。

投资组合构建

我们提出了一个框架来检查配对交易的盈利能力。特别地,我们说明了如何调整头寸以增强均值回归,并研究了使用优化退出规则对不同配对交易策略的风险和回报的影响。

对于日内价格,我们考虑以下形式的投资组合:

我们将任何给定的投资组合价值拟合到一个奥恩斯坦-乌伦贝克(OU)过程

通过最大似然估计(MLE) ,我们优化了平均对数似然:

在哪里

结对交易是一种直观的策略,任何严肃的结对交易系统都必须包括一个优化仓位的程序,以及进场和出场的时间。

在观察当前市场价格时,交易者可以选择立即建立配对交易头寸,也可以等待。开始配对交易后,交易者需要决定何时平仓。

使用最优退出规则如何提高配对交易的盈利能力?我们考虑分析最优策略,公式由 Leung & Li (2015) 得出,其中头寸以最优退出价格平仓。然后,我们将它的表现与基线策略进行比较,在价差的标准偏差下进场和出场。除了作为 OU 模型拟合的一部分的对比率和参数选择之外,没有尝试对性能进行优化。

绩效总结

如下表和下图所示,使用最优退出规则可以提高盈利能力,减少交易,从而降低交易成本。

所有 8 对投资组合的绩效总结,有和没有最佳退出。从上到下,我们报告了年化回报、年化标准差、夏普比率、最大提取、每次周转的回报、每日回报、每日周转、累计 PnL 和累计交易成本。

黄金(GC)和白银(SI)交易对:具有最佳退出规则的策略(红色)始终优于基线策略(蓝色)。

点击此处对上述所有配对的全面分析(pdf)。

关联的 python 包可用。这里有一个说明性的用户指南:

https://medium . com/quantitative-investing/a-python-package-for-optimal-mean-reversion-trading-80a 21814520d

参考

D.Lee 和 T. Leung(2020),关于均值回归交易的优化退出规则的有效性,国际金融工程杂志。【https://doi.org/10.1142/S2424786320500243

J.张,A. Aravkin 和 T. Leung (2020),通过惩罚似然优化的稀疏均值回复投资组合,自动化,第 111 卷,108651。https://doi.org/10.1016/j.automatica.2019.108651

T.Leung T .和 X. Li (2016),最优均值回归交易:数学分析和实际应用,世界科学出版公司(2016)

T.Leung T .和 X. Li (2015),有交易成本的最优均值回复交易&止损退出,国际理论&应用金融杂志,第 18 卷,第 3 期,第 1550020 页。https://doi.org/10.1142/S021902491550020X

谷歌学术 // 领英页面 // 主页

来自《走向数据科学》编辑的注释: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

熊猫申请电力用户

原文:https://towardsdatascience.com/pandas-apply-for-power-users-f44d0e0025ce?source=collection_archive---------41-----------------------

通过学习熊猫内置的 apply()函数成为超级用户

由托德·特拉帕尼在 Unsplash 拍摄的照片

介绍

在我们的数据科学职业生涯中,我们会遇到质量差的数据,无论是部分完成的记录还是格式不正确的属性。作为一名成功的数据科学家,能够管理质量差的数据已经成为一项至关重要的技能。

令人欣慰的是,已经开发了许多库,如 Pandas ,我们可以用它们来有效地操作数据集。今天我们来看看如何利用熊猫的内置功能。apply()学习如何操作数据集。

熊猫应用功能

pandas apply 函数顾名思义,它允许你在一个数据帧的轴上或一个系列上应用一个函数。当需要在重新格式化或清理数据的情况下操作列或行时,这个函数非常强大。

显示应用函数及其参数的 Python 代码片段

第一个参数func允许你传入一个函数。这可以是一个导入包中的函数,一个你在脚本中声明的函数,甚至是一个 lambda 函数。下面的 python 代码片段演示了如何在第 21–23 行之间传递三种不同类型的函数。这里我们通过传递产生相同结果的三个不同的函数来创建由 Pandas .apply()函数生成的三个新列。

Python 代码片段显示了可以传递给应用函数的不同类型的函数。

控制台输出显示了执行上述代码片段的结果。

第二个参数axis允许您定义函数将应用于哪个轴。这可以是数据框中行的0index,也可以是列的1columns。就个人而言,我更喜欢使用indexcolumns,因为对于那些不理解01背后含义的人来说,这可以提高代码的可读性。第三个参数raw决定传递的是行还是列,还是 n 维数组( ndarray )对象。如果raw=False被传递,则行或列作为系列被传递给应用函数,如果raw=True被传递,则 ndarray 对象被传递给函数。

参数result_type改变应用函数如何应用于数据帧的列轴。默认情况下result_type设置为None,但是,可以接受expand broadcastreduce。如果expand被传递,则返回的任何列表类型结果都将跨列展开。如果返回列表的长度大于数据帧中的列数,则将创建额外的列来扩展。在列表扩展期间,数据帧的原始列名将被覆盖为范围索引。如果需要保留数据框的原始形状,那么可以传递broadcast,这也将确保保留原始的列名。如果你需要确保列表类型的结果不被扩展,那么你可以将reduce传递给result_type

Python 代码片段显示了熊猫应用结果类型可以接受的不同参数。

最后一个参数args=()允许您将值传递给正在应用的函数。在下面的例子中,我们将传递2575作为函数between_range()lowerhigher参数。当该函数应用于该列时,将评估result系列中的每个值是在该值范围之内还是之外,并将在in_range列中返回一个布尔值。

Python 代码片段展示了如何将 arge=()与 Pandas 内置函数 apply()一起使用。

显示在 args=()内调用 between_range()的结果的控制台输出。

摘要

Pandas 内置的 apply()函数是一个非常强大的工具,在处理质量差的数据时,它是一个非常好的工具。它提供了一种沿数据帧的轴应用函数来清理或操作数据的有效方法。apply()函数可以灵活地传递参数,这将允许您处理几乎所有的数据质量问题。

感谢您花时间阅读我们的故事,我们希望您已经发现它的价值:)

数字之外的熊猫:使用文本数据

原文:https://towardsdatascience.com/pandas-beyond-numbers-working-with-textual-data-19cf353b23a5?source=collection_archive---------23-----------------------

举例说明。

照片由 Aaron Burden 在 Unsplash

Pandas 是使用最广泛的 Python 数据分析和操作库。由于数据并不总是以清晰的数字表示,数据分析库应该能够处理任何格式的数据。熊猫做到了,而且做得很好。

在这篇文章中,我们将探索熊猫的文本数据(如字符串)的能力。让我们从文本数据的数据类型开始。

对象与字符串

在 pandas 1.0 之前,只有“object”数据类型用于存储字符串,这导致了一些缺点,因为非字符串数据也可以使用“object”数据类型来存储。例如,具有对象数据类型的列可以包含数字、文本、日期和列表,这对于数据分析来说不是最佳方式。

Pandas 1.0 引入了一种新的特定于字符串数据的数据类型,即string type。到目前为止,我们仍然可以使用 object 或 string type 来存储字符串,但是在将来,我们可能会被要求只使用 string type。

到目前为止,“object”仍然是存储字符串的默认数据类型。为了使用 StringDtype,我们需要显式地声明它。

import pandas as pdpd.Series(['aaa','bbb','ccc']).dtype
dtype('O')pd.Series(['aaa','bbb','ccc'], dtype='string').dtype
StringDtypepd.Series(['aaa','bbb','ccc'], dtype=pd.StringDtype()).dtype
StringDtype

如果“字符串或 **pd,则使用 StringDtype。string type()**作为参数传递给 Dtype 参数。

我们需要文本数据来处理。我会先从熊猫的维基百科页面获取一段,并存储在一个列表中。

text = ["Developer Wes McKinney started working on pandas in 2008 while at AQR Capital Management out of the need for a high performance, flexible tool to perform quantitative analysis on financial data. Before leaving AQR he was able to convince management to allow him to open source the library."]

文本是只有一项的列表。我将把它转换成一个熊猫系列,将每个单词作为一个单独的项目。

A = pd.Series(text).str.split().explode().reset_index(drop=True)A[:5]
0    Developer 
1          Wes 
2     McKinney 
3      started 
4      working 
dtype: object

Str 是访问字符串操作的属性。顾名思义,Split 根据指定的字符(默认为空格)拆分数据。然后,我们使用 explode 函数将每个分离的单词作为系列中的一个新项目。

如果我们不重置索引,由于 explode 函数的性质,序列 A 中的所有项目的索引都将为 0。值得一提的是,还有其他方法来创建一个文字系列,这是关于熊猫的一件好事。它几乎总是提供多种方法来完成一项任务。

有些单词以大写字母开头,这在数据分析中是不可取的。我们希望尽可能有一个标准。我们可以将它们全部转换成大写或小写字母。

A.str.upper()[0]
'DEVELOPER'A.str.lower()[0]
'developer'

所有项目都已转换,但我们只访问了第一个项目。

len 函数返回对象的长度。如果是列表,len 返回列表中的项数。如果 len 与 str 属性一起使用,它将返回每个字符串的长度。

A.str.len()[:5]
0    9 
1    3 
2    8 
3    7 
4    7

如果您想将此系列中的所有字符串组合回其原始格式,您可能会使用的函数是 cat :

A.str.cat(sep=" ")developer wes mckinney started working on pandas in 2008 while at aqr capital management out of the need for a high performance, flexible tool to perform quantitative analysis on financial data. before leaving aqr he was able to convince management to allow him to open source the library.

字符串操作提供了很大的灵活性。例如,我们不仅可以用其他字符串替换一个字符串,还可以替换一个字符串的一部分(即按字符)。

A.str.replace('the', 'not-a-word')[-3:]
45        source 
46    not-a-word 
47      library.A.str.replace('deve', ' ')[:3]
0       loper 
1         wes 
2    mckinney

str 访问器提供对字符串字符的索引。例如,我们只能得到前 3 个字符。如果在一个字符串的末尾或开头有一些多余的字符,这就很方便了。

first_three = A.str[:3]first_three[:2]
0    dev 
1    wes

熊猫字符串方法也兼容正则表达式 (regex)。正则表达式的整个范围太详细了,但是我们将做几个简单的例子。假设我们有包含一个字母和一个数字的字符串,那么模式就是字母-数字。我们可以用这个模式提取部分字符串。

B = pd.Series(['a1','b4','c3','d4','e3'])B.str.extract(r'([a-z])([0-9])')

我们可能还想检查是否所有的字符串都有相同的模式。

C = pd.Series(['a1','4b','c3','d4','e3'])C.str.contains(r'[a-z][0-9]')

我们还可以计算字符串中特定字符的数量。

B = pd.Series(['aa','ab','a','aaa','aaac'])B.str.count('a')
0    2 
1    1 
2    1 
3    3 
4    3

在某些情况下,我们可能需要根据条件过滤字符串。例如,startswith 和 endswith 函数可以与 str 属性一起使用。

B = pd.Series(['aa','ba','ad'])B.str.startswith('a')
0     True 
1    False 
2     TrueB.str.endswith('d')
0    False 
1    False 
2     True

一些机器学习算法需要对分类变量进行编码。str 属性支持 get_dummies 函数。

cities = ['New York', 'Rome', 'Madrid', 'Istanbul', 'Rome']pd.Series(cities).str.get_dummies()

Pandas 字符串操作并不局限于我们在这里讨论的内容,但是我们讨论的函数和方法肯定会有助于处理字符串数据并加快数据清理和准备过程。

感谢阅读。如果您有任何反馈,请告诉我。

熊猫小抄

原文:https://towardsdatascience.com/pandas-cheat-sheet-4c4eb6802a4b?source=collection_archive---------12-----------------------

使用 Python 与熊猫一起行动

照片由戴安娜·西拉瑞亚从派克斯拍摄

掌握一项技能的 10000 小时法则

在他的名著《局外人》中,马尔科姆·格拉德威尔曾经说过,一个人需要投入 10000 个小时才能成为任何技能的真正大师。这背后的想法是熟能生巧,这是另一个已经铭刻在一些人心中的流行说法。

虽然我当然同意,随着时间的推移,一项新技能的不断练习和重复会形成一致的习惯和表现,但很难想象有人在任何时候都知道一切。如果你曾经对熊猫进行过任何数据分析,有一些基本的功能是你不需要的。

这是熊猫基本功能的备忘单。

入门指南

对于这个小抄,我们将创建一个学校不同科目的成绩的小型数据框架。先从进口熊猫说起吧。

# import the package
import pandas as pd# creating a dataframe with all the grades and subjects
grades = pd.DataFrame({'Math'     : [80, 89, 93,66, 84, 85,74,64],'Science'  : [94, 76, 88, 78, 88, 92, 60, 85],'English'  : [83, 76, 93, 96, 77, 85, 92, 60],'History'  : [96, 66, 76, 85, 78, 88, 69, 99]})

为了显示数据框的顶部,我们可以使用 head 功能。默认情况下,我们将获得前 5 行。如果我们想要另一个数字,我们可以将一个特定的数字作为 n 传递。

# first 5 rows
grades.head()# first 10 rows
grades.head(n = 10)

尾巴

类似地,我们可以通过调用数据帧上的 tail 来获得最后 5 行,并传递 n 作为参数来更改显示的数字,从而获得与head相反的结果。

# last 5 rows
grades.tail()# last 10 rows
grades.tail(n = 10)

如果我们只想用数据帧的命名,我们可以使用.columns函数

# column names
grades.columns

输出如下→ Index(['数学','科学','英语','历史'],dtype= '对象')

形状

如果您正在处理大型数据框,并且很难手动计算行数或列数,我们使用.shape来查找维度。

# size of the dataframe
grades.shape

信息

在开始任何分析之前,了解您正在处理的数据类型是很重要的。使用.info()您可以了解您拥有的数据类型的概况。

# data types
grades.info()

在我们的例子中,所有的数据都是整数类型,因为我们对每个年级都使用整数。

形容

.info()一样,您很可能想知道数据报的描述性统计数据。使用.describe()可以观察计数、平均值、标准偏差、数量、最小值、最大值。在这个例子中,我使用了.round(2)来清理输出。

# descriptive statistics with chained round
grades.describe().round(2)

分位数

使用.describe()函数,我们自动获得了 25、50 和 75 的分位数。我们也可以陈述我们自己的分位数。下面我选了 10%、40%、70%。注意——我们可以在下面的公式中传递尽可能多的分位数。

# quantitles
grades.quantile([0.1,0.4,0.7, 0.8, 0.9])

平均值、标准差、方差、计数、中值、最小值和最大值

我们可以在数据帧上使用各种函数来获得聚合结果。您也可以传入一个列名,以便只检索该列的值。

# mean
grades.mean()
grades['Math'].mean()# standard deviation
grades.std()
grades['Math'].std()# variance
grades.var()
grades['Math'].var()# count
grades.count()
grades['Math'].count()# median
grades.median()
grades['Math'].median()# min
grades.min()
grades['Math'].min()# max
grades.max()
grades['Math'].max()

重命名列

如果我们要重命名列,例如,将列名改为大写的*。*

*# using inplace means making change to itself. 
grades.rename(columns = {'Math':'MATH'}, inplace = True)# if we don't state inplace as True we need to save it back to itself manually
grades = grades.rename(columns = {'Math':'MATH'})*

上面两段代码将返回相同的结果。inplace = True利用这个论证,我们告诉它要把它保存到自身中去,并记住结果。如果我们不声明inplace = True,我们将不得不在=中编码,以声明我们希望将值保存回等级数据帧中。

索引子集设置— iloc

使用代表索引位置的 iloc,我们可以根据索引位置找到数据帧的子集。我们可以通过多种方式建立索引,因此了解使用下面的 iloc 的不同变化非常重要。iloc 的第一部分代表行,第二部分代表列。

如果你以前在 Python 中不知道这一点,索引从 0 开始。这意味着第一个数字将是索引 0 ,而不是索引 1。

*# iloc - indexinggrades.iloc[0]           # first column
grades.iloc[[0]]         # frist row
grades.iloc[:, 1]        # all rows second column
grades.iloc[3, 1]        # 4th row second column only
grades.iloc[[1,3], :]    # row 1 and 3, with all columns
grades.iloc[:, 1:3]      # all rows and columns 1 to 3 (*not                              including 3)
grades.iloc[4:, : 3]     # from row 5 till last row, and first col to 4th col (not including 4th)*

注意我们在某些情况下包含了一个::代表范围符号,:左边的数字表示起始位置,右边的数字表示索引到的位置,但不包括。例如grades.iloc[:, 1:3]它被分成两部分。

  1. 第一个: →所有行,因为它前面没有开始索引,后面也没有结束索引
  2. 第二个1:3 →从第栏 1 起,但不包括第栏 3。这意味着在本例中,结果将只返回第 1 列和第 2 列。

位置子集 loc

与子集化相反,我们有基于位置的子集化。这里我们引用我们需要的变量的名字,而不是索引。

*grades.loc[:, 'Math']                  # all rows in Math column
grades.loc[2:3, ['Math', 'English']]   # rows 3 and 4, for Math and English
grades.loc[4:, 'Math': 'English']      # row 5 onwards, and Math TO English
grades.loc[:5, 'Science': ]*

对于我们的数据,我们只有列的位置子集名称。如果我们有行标签,我们也可以引用它们。我们将在后面看到这个例子。

排序值

如果我们想根据特定的值对数据帧进行排序,我们可以使用sort_values()默认情况下,值按升序排序,我们可以传入一个 False 参数,将其更改为降序

*# sort by a column - default asc
grades.sort_values('Math')
grades.sort_values('Math', ascending = False)*

串联

使用 concat,我们可以基于一个轴将两个数据框合并在一起。例如,我们可以在两种情况下向数据帧添加新值。

  1. 添加更多行—轴= 0
  2. 添加更多列—轴= 1
*# concat
grades2 = pd.DataFrame({'Math'     : [77,55,93,76],'Science'  : [88,60,90,74],'English'  : [84,76,66,90],'History'  : [77,69,92,81]})# attach dataframes together, reset index and drop the index col
pd.concat([grades, grades2], axis = 0).reset_index(drop=True)*

首先,我们创建了第二个包含附加等级值的数据框,称为等级 2 。然后我们把新的数据帧放到旧的数据帧上。我们将轴标为 0,因为我们添加了更多的行。如果我们要添加一个全新的主题,比如 Geography,,那么我们希望使用 axis = 1。

如果我们没有添加reset_index,指数就不会排成一行。下面是它的样子。

使用reset_index(drop=True)我们正在做两件事。让指数组织起来,回到一个连续的形式。我们删除索引是因为 pandas 会自动创建一个额外的索引列,这是我们不需要的——所以我们删除了它。

布尔索引

熊猫中一个有用的技术叫做布尔索引。它本质上是一种基于布尔条件(即真或假)查找值的过滤技术。布尔索引的一般语法如下。

*dataframe[dataframe['column_name'] == 'filter_objective']*

使用布尔索引,我们需要在括号内重述数据帧。

*# boolean subseting
grades[grades['Math'] > 80]# subsetting but only calling a column
grades[grades['Math'] > 80]['Science']# subsetting but only calling a column using iloc
grades[grades['Math'] > 80].iloc[:, 3]# AND  conditions
grades[(grades['Math'] > 80) & (grades['Science'] < 80)]# OR conditions but only want History score
grades[(grades['Math'] > 80) | (grades['Science'] < 80)]['History']*

如上所述,我们可以组合多个布尔条件来深化过滤能力。使用&|我们可以陈述条件。如果两个条件都满足,& (AND)将返回结果。如果条件的任何一方得到满足,| (OR)将返回结果。

观察上面的代码。我们可以看到,添加 iloc 或列名可以为我们提供一个结果,如果满足条件,则只返回所选的列。

子集化列

您可以将 pandas 中的列子集化为一个系列或一个数据框架。

系列是 pandas 中的一种列表类型,可以接受整数值、字符串值、双精度值等等。但是在熊猫系列中,我们以列表的形式返回一个对象,索引从 0n ,其中 n 是系列中值的长度。系列只能包含一个带索引的列表,而数据帧可以由多个系列组成,或者我们可以说数据帧是可用于分析数据的系列的集合。

*# subseting a column as a series
grades['Math']# subseting as a dataframe
grades[['Math']]# multiple columns
grades[['Math', 'History']]*

添加列

向 dataframe 中添加更多的列就像创建一个新的列名并设置与之相等的值一样简单。

*# new columns
grades['Student']   = ['Tom', 'Jane', 'Mike', 'Jason', 'Kim', 'Stephanie', 'Mary', 'Jack']
grades['Gender']    = ['M','F', 'M', 'M', 'F', 'F', 'F', 'M']
grades['Class']     = ['A', 'A', 'C', 'B', 'C', 'A', 'B', 'C']*

重新排列列

如果是上面的例子,将学生作为第一列会更有意义。如果我们想对列进行重新排序,我们可以创建一个我们希望数据帧列的顺序列表,并在数据帧上对它们进行索引。

*# reorder columns - pass a list as a list and index#order we want
cols = ['Student', 'Class','Gender', 'Math', 'Science', 'English','History']# overwrite the old dataframe with the same dataframe but new column order
grades = grades[cols]*

数据透视表

数据透视表是一个统计表,它汇总了一个更大的表(例如来自数据库、电子表格或商业智能程序)的数据。该汇总可能包括总和、平均值或其他统计数据,数据透视表以一种有意义的方式将它们组合在一起。

数据透视表是数据处理中的一项技术。他们安排和重新安排(或“旋转”)统计数据,以引起对有用信息的注意。

*# pivot tables
grades.pivot_table(index= ['Class','Gender'])*

我们可以看到,我们首先根据值的类别对值进行分组,然后根据性别进行分组。这提供了数据帧的聚合结果。

分组依据

一个 groupby 操作包括分割对象、应用函数和组合结果的某种组合。这可用于对大量数据进行分组,并对这些组进行计算操作。

*# groupby combined with aggreagate function
grades.groupby(by ='Gender').mean()*

按性别分组,平均值

pandas 中的groupby函数的伟大之处在于使用agg函数链接了几个聚合函数。

*# groupby and adding several funcitons with agg
grades.groupby(by ='Class').agg(['sum', 'mean']).round(2)*

概观

我希望这能给你提供在熊猫身上使用的新工具,或者刷新你对已有知识的记忆。记住,要坚持练习,如果你能达到所谓的“大师”水平,马尔科姆·格拉德威尔说,也许有一天,你将不再需要小抄来参考。

LinkedinGithub 上与我联系

熊猫小抄

原文:https://towardsdatascience.com/pandas-cheat-sheet-7e2ea6526be9?source=collection_archive---------22-----------------------

Python 数据分析库 Pandas 基础知识快速指南,包括代码示例。

由马尔科·汉克基拉在 Unsplash 上拍摄的照片

我最喜欢的教授告诉我“软件工程师读教科书是作为参考;我们不会记住所有的东西,但我们知道如何快速查找。”

能够快速查找和使用函数允许我们在进行机器学习模型时实现一定的流程。所以我创建了这个熊猫函数的备忘单。这不是一个全面的列表,但包含了我在建立机器学习模型时最常用的函数。让我们开始吧!

这张纸条的结构是:

  1. 输入数据
  2. 导出数据
  3. 创建测试对象
  4. 查看/检查数据
  5. 选择
  6. 数据清理
  7. 筛选、排序和分组依据
  8. 统计数字

首先,我们需要进口熊猫来开始:

import pandas as pd

来源: gacafe。Github

1.输入数据

使用功能pd.read_csv将 CSV 直接转换成数据帧。

N 注意:对于 excel 文件,还有另一个类似的函数叫做pd.read_excel

# Load data 
df = pd.read_csv('filename.csv') # From a CSV file
df = pd.read_excel('filename.xlsx') # From an Excel file

2.导出数据

to_csv()转储到与笔记本相同的目录。我们可以通过df[:10].to_csv()保存前十行。我们还可以使用df.to_excel()将数据帧保存并写入 Excel 文件或 Excel 文件中的特定表格

df.to_csv('filename.csv') # Write to a CSV file
df.to_excel('filename.xlsx') # Write to an Excel file

3.创建测试对象

从输入的数据构建数据帧

当我们想要手动实例化简单数据以查看数据流经管道时的变化时,这很有用。

# Build data frame from inputted data
df = pd.DataFrame(data = {'Name': ['Bob', 'Sally', 'Scott', 'Katie'],'Physics': [68, 74, 77, 78],'Chemistry': [84, 100, 73, 90],'Algebra': [78, 88, 82, 87]})

df

或者从列表中创建一个系列

#  Create a series from an iterable my_list
my_list = [['Bob',78],['Sally',91], ['Scott',62],['Katie',78],['John',100]]
df1 = pd.Series(my_list) # Create a series from an iterable my_list

df1

4.查看/检查数据

头部(),尾部()

head()功能显示数据帧中的第一个n记录。我经常把一个数据帧的最上面的记录打印在笔记本上,这样如果我忘记了里面的内容,就可以回头查阅。

df.head(3) # First 3 rows of the DataFrame

df.head()

tail()函数用于返回最后 n 行。这对于快速验证数据非常有用,尤其是在排序或追加行之后。

df.tail(3) # Last 3 rows of the DataFrame

df.tail()

添加或插入行

为了向 DataFrame 追加或添加一行,我们创建新行作为系列并使用append()方法。

在本例中,新行被初始化为 python 字典,使用append()方法将该行追加到 DataFrame。

当我们向append(),添加 python 字典时,确保我们传递了ignore_index=True,,这样索引值就不会沿着串联轴使用。结果轴将被标记为数字序列0, 1, ..., n-1,这在串联轴没有有意义的索引信息时很有用。

append()方法返回带有新添加行的 DataFrame。

#Append row to the dataframe, missing data (np.nan)
new_row = {'Name':'Max', 'Physics':67, 'Chemistry':92, 'Algebra':np.nan}
df = df.append(new_row, ignore_index=True)

df

向数据帧添加多行

# List of series  
list_of_series = [pd.Series(['Liz', 83, 77, np.nan], index=df.columns),pd.Series(['Sam', np.nan, 94,70], index=df.columns ),pd.Series(['Mike', 79,87,90], index=df.columns),pd.Series(['Scott', np.nan,87,np.nan], index=df.columns),]
# Pass a list of series to the append() to add multiple rows
df = df.append(list_of_series , ignore_index=True)

df

或者我们可以添加新的列

# Adding a new column to existing DataFrame in Pandas
sex = ['Male','Female','Male','Female','Male','Female','Female','Male','Male']
df['Sex'] = sex

df

获取数据帧信息

info()函数对于获取一些常规信息很有用,比如标题、值的数量和列的数据类型。一个类似但不太有用的函数是df.dtypes,它只给出列数据类型。

df.info() #Index, Datatype and Memory information

df.info()

# Check data type in pandas dataframe
df['Chemistry'].dtypes 
>>> dtype('int64')#  Convert Integers to Floats in Pandas DataFrame
df['Chemistry'] = df['Chemistry'].astype(float) 
df['Chemistry'].dtypes
>>> dtype('float64')# Number of rows and columns
df.shape 
>>> (9, 5)

计算唯一的行

value_counts()函数用于获取包含唯一值计数的序列。

# View unique values and counts of Physics column
df['Physics'].value_counts(dropna=False)

5.选择

获取列的值列表或系列

如果我们需要将列中的值放入Xy变量中,这样我们就可以适应机器学习模型,这样就可以了。

df['Chemistry'] # Returns column with label 'Chemistry' as Series

df[['Name','Algebra']] # Returns columns as a new DataFrame

df.iloc[0] # Selection by position

df.iloc[:,1] # Second column 'Name' of data frame

df.iloc[0,1] # First element of Second column
>>> 68.0

6.数据清理

重命名列

rename()当我们需要重命名一些选定的列时,该功能非常有用,因为我们只需要为要重命名的列指定信息。

# Rename columns
df = df.rename({'Name':'Student','Algebra':'Math'}, axis='columns')

df

处理熊猫中缺失的数据

在 DataFrame 中,有时许多数据集只是在到达时丢失了数据,要么是因为它存在而未被收集,要么是因为它从未存在过。

NaN(非数字的首字母缩写)是一个特殊的浮点值,被所有使用标准 IEEE 浮点表示法的系统所识别

熊猫将NaN视为本质上可互换的,用于指示缺失值或空值。为了促进这种约定,有几个有用的函数用于检测、删除和替换 Pandas 数据帧中的空值。

# Checks for null Values, Returns Boolean Arrray
check_for_nan = df.isnull()

为 nan 检查

为了检查 Pandas 数据帧中的空值,我们使用了isnull()notnull()方法。isnull()方法返回对 NaN 值为真的布尔值的数据帧。在相反的位置,notnull()方法返回布尔值的数据帧,对于 NaN 值为假。

value = df.notnull() # Opposite of df2.isnull()

价值

我们使用dropna()函数删除所有缺少值的行。

drop_null_row = df.dropna() # Drop all rows that contain null values

删除空行

有时,我们可能只想删除一个缺少一些值的列。

# Drop all columns that contain null values
drop_null_col = df.dropna(axis=1)

删除空列

我们可以通过使用fillna()来填充缺失的值。例如,我们可能希望用零替换“NaN”。

replace_null = df.fillna(0) # Replace all null values with 0

替换空值

或者我们可以用平均值代替 NaN。

# Replace all null values with the mean (mean can be replaced with almost any function from the statistics module)
df = round(df.fillna(df.mean()),2)

df

replace()方法可以用来替换数据帧中的值

one = df.replace(100,'A') # Replace all values equal to 1 with 'one'

一个

7.筛选、排序和分组依据

按行值过滤熊猫数据帧

我们希望看到物理成绩达到 80 分或更高的学生

fil_80 = df[df['Physics'] > 80]

fil_80

如果我们想看到化学得 80 分或更高,但数学考试不到 90 分的学生怎么办

fil = df[(df['Chemistry'] > 80) & (df['Math'] < 90)]

费尔(伊拉克的钱币)

排序值()

我们经常想以特定的方式对熊猫数据帧进行排序。通常,可能希望根据一个或多个列的值对 Pandas 数据帧进行排序,或者根据 Pandas 数据帧的行索引值或行名进行排序。

例如,我们希望按学生姓名以升序对值进行排序。

ascending = df.sort_values('Student')

上升的

按降序排列化学分数。

descending = df.sort_values('Chemistry',ascending=False)

下降

更复杂的是,我们想按物理分数升序排序,然后按化学分数降序排序。

df.sort_values(['Physics','Chemistry'],ascending=[True,False])

在这种情况下,数据帧将分别针对物理和化学列进行排序。我们还可以向' ascending '参数传递一个列表,告诉 Pandas 对哪一列如何排序。

groupby()

Groupby 是一个非常简单的概念。我们可以创建一组类别,并对这些类别应用一个函数。这是一个简单的概念,但却是我们经常使用的一个非常有价值的技术。Groupby 概念很重要,因为它能够高效地聚合数据,无论是性能还是代码量都非常可观。

让我们对性别列中的唯一值进行分组

group_by = df.groupby(['Sex']) # Returns a groupby object for values from one column
group_by.first() # Print the first value in each group

group_by.first()

计算每个唯一性别组的所有列的平均值

average = df.groupby(‘Sex’).agg(np.mean)

平均的

8.统计数字

我们可能熟悉 Excel 中的数据透视表,以便轻松洞察我们的数据。类似地,我们可以使用 Pandas 中可用的pivot_table() 函数创建 Python 数据透视表。该功能与group_by()功能非常相似,但是提供了更多的定制功能。

假设我们要按性别对值进行分组,并计算物理和化学列的平均值和标准差。我们将调用pivot_table()函数并设置以下参数:

  • index'Sex',因为这是来自df的列,我们希望在每一行中显示为唯一值
  • values as 'Physics','Chemistry'因为这是我们想要应用一些聚合操作的列
  • aggfunc'len','np.mean','np.std len将计算性别列中唯一的不同值,np.meannp.std将分别计算平均值和标准差。
pivot_table = df.pivot_table(index='Sex',values=['Physics','Chemistry'],aggfunc=[len, np.mean, np.std])

数据透视表 _ 表格

N 注意:使用len假设我们的数据报中没有NaN值。

describe() 用于查看一些基本的统计细节,如百分位数、平均值、标准差等。一个数据帧或一系列数值。

df.describe() # Summary statistics for numerical columns

描述()

使用max()找到每行和每列的最大值

# Get a series containing maximum value of each row
max_row = df.max(axis=1)

最大行数

# Get a series containing maximum value of each column without skipping NaN
max_col = df.max(skipna=False)

max_col

同样,我们可以用df.min()来求每行或每列的最小值。

其他有用的统计功能:

df.sum():返回所请求轴的值的总和。默认情况下,轴是索引(轴=0)。

df.mean():返回平均值

df.median(): 返回每列的中值

df.std():返回数值列的标准偏差。

df.corr() :返回数据帧中各列之间的相关性。

df.count():返回每列中非空值的个数。

本笔记中的代码可从 Github 获得。

这些都是好东西。希望这张小抄能成为你的参考指南。随着我发现更多有用的熊猫功能,我会不断更新。如果有什么你离不开的功能,请在下面的评论中与我分享!

学习永远不会太迟,所以如果你刚刚开始你的 Python 之旅,继续学习吧!

来源: quantumcomputingtech

已经有很多很多关于 Python 编程的书籍。我当然没有涵盖足够的信息来填补一个章节,但这并不意味着你不能继续学习!从下面的链接开始,让你的头脑充满更多的精彩。

  1. 熊猫装置
  2. Python 手册
  3. 熊猫初学者入门
  4. 熊猫基础知识
  5. 如何学习熊猫
  6. 熊猫在 Python 中有什么用

熊猫:组合数据

原文:https://towardsdatascience.com/pandas-combining-data-b190d793b626?source=collection_archive---------76-----------------------

PyTrix 系列

PyTrix #5:对熊猫进行更多的数据操作

美国宇航局在 Unsplash 拍摄的照片

Pandas 框架配备了SeriesDataFrame对象,它们是数据探索和分析的强大工具。这些对象拥有的部分能力可以归因于它们采用多方面的方法来组合单独的数据集。Pandas 提供的功能允许你合并连接连接追加数据。然而**,在我看来我发现只需要学习 2 个就是合并串联**这里是为什么:

df.append():将 other 的行追加到调用者的末尾,返回一个新的对象。

pd.concat():沿特定轴连接熊猫对象,沿其他轴连接可选的集合逻辑。

df.join():连接另一个数据框架的列。

pd.merge():用数据库风格的连接合并数据帧或命名系列对象。

注:所有描述均来自官方熊猫 文档

阅读组合数据的不同方法的细节,您可能会注意到df.append()pd.concat()本质上具有非常相似的功能,但是pd.concat()更加灵活。同样,df.join()pd.merge()具有相似的功能,但是pd.merge()df.join()提供了更多的灵活性。出于这个原因,我认为更有必要对pd.concat()pd.merge()都有很好的理解,并使用这些顶级函数来完成你在 pandas 中的所有组合——在我看来。

“应该有一种——最好只有一种——显而易见的方法来做到这一点,”Python 的 Zen。

对于这个故事,我将使用pandas和来自seaborn的提示数据集来演示每个功能。让我们载入数据…

**import** **pandas** **as** **pd** 
**import** **seaborn** **as** **sns***# load tips data from seaborn* 
data = sns.load_dataset("tips")
print(data.shape)
data.head()>>>> (244, 7)

图 1:上面代码块中生成的代码的结果;来自 seaborn 的 Tips 数据集。

您可能会立即注意到只有一个数据集。为了组合数据,我们需要多个数据集,因此我将数据集分成两个数据帧——我们假设这两个数据集是分开的。

*# splitting the data into two seperate df* 
bill = data.groupby(["sex", "smoker"])["total_bill", "tip"].sum()
tip = bill.copy() 
*# removing bill from tip and tip from bill* 
**del** tip["total_bill"]
**del** bill["tip"]# *visualizing bill dataset*
bill.reset_index(inplace= **True**)
print(bill.shape)
bill.head()>>>> (4, 3)

图 2:账单数据集

让我们看看 tip 数据框是什么样子的…

# visualizing tip dataset
tip.reset_index(inplace= **True**) 
print(tip.shape)
tip.head()>>>> (4, 3)

图 3: Tip 数据集

本故事中使用的代码可以在以下位置找到:

[## kurtispykes/演示

github.com](https://github.com/kurtispykes/demo/blob/master/pytrix/pytrix_combing_data_in_pandas.ipynb)

合并

在展示pd.merge()的一些功能之前,让我们花点时间来理解我们可以连接数据的不同方式:

注意:如果您熟悉 SQL,那么您可能会从JOIN语法中认出不同的操作名。

  • 内部联接 —选择在两个数据帧中具有匹配值的记录。
*# Inner join* 
inner_join = pd.merge(bill, tip, how="inner", on=["sex", "smoker"])
print(inner_join.shape)
inner_join.head()>>>> (4, 4)

图 4:对我们的数据执行内部连接

  • 外部连接 —外部连接将从左侧和右侧数据帧返回所有记录。如果数据帧列中没有匹配,不匹配的结果将用nan填充。
*# Outer join* 
outer_join = pd.merge(bill.tail(2), tip.head(2), how= "outer", on=["sex", "smoker"], indicator=**True**)
print(outer_join.shape)
outer_join.head()>>>> (4, 5)

图 5:数据帧上的外部连接;请注意,有一个额外的“_merge”列指示合并是如何完成的。这是因为在 pd.merge()中将 indicator 设置为 True。

  • 左连接 —左连接将返回左表中的所有记录,以及右表中的匹配记录。对于只存在于左侧数据帧中的键,右侧数据帧中不匹配的值将用nan填充。
# left join
left_join = pd.merge(bill, tip.head(2), how= "left", on=["sex", "smoker"], indicator=**True**)
print(left_join.shape)
left_join.head()>>>> (4, 5)

图 6:左连接数据帧

  • 右连接 —右连接将返回右数据帧中的所有记录,以及左数据帧中的匹配记录。对于只存在于右侧数据帧中的键,左侧数据帧中不匹配的值将用nan填充。
*# Right join*
right_join = pd.merge(bill.head(2), tip, how= "right", on=["sex", "smoker"], indicator= **True**)
print(right_join.shape)
right_join.head()>>>> (4, 5)

图 7:右连接数据帧

图 8 为我们提供了上述不同连接的可视化表示。

图 8:不同连接的可视化表示;假设维恩图中的两个圆是两个数据帧。此外,我们还必须假设外部连接指示两个数据帧(集合并集)中的所有内容,而不是两个数据帧之外的所有内容。

有时,您想要合并的数据帧中的列可能是不同的,但是跨两个数据帧的索引是相同的。例如,按日期分组的显示开盘价的财务数据可以是一个数据框架,而按日期分组的显示收盘价的财务数据可以是另一个数据框架。我们可以使用pd.merge()合并指数上的数据框架,这将导致一个数据框架显示特定日期的开盘价和收盘价。

这里有一个例子:

*# Setting indexes* bill.set_index(keys= ["sex", "smoker"], inplace= **True**) tip.set_index(keys= ["sex", "smoker"], inplace= **True**)bill.head()

图 9:以“性”和“吸烟者”为索引的账单数据框架

tip.head()

图 10:以“性别”和“吸烟者”为索引的 Tip 数据框架

*# Merging on index*
index_merge= pd.merge(bill, tip, how="inner", left_index=**True**, right_index=**True**)
index_merge.head()

图 11:索引合并

通过简单地将left_indexright_index设置为True,我们可以在索引上进行合并。此外,通过将一个要合并的索引设置为True,并定义与另一个数据帧中的索引相匹配的列,可以合并索引和列。例如…

*# Merging partial index and column* 
partial_merge= pd.merge(bill, tip, how="inner", left_index=**True**, right_on=["sex", "smoker"])
partial_merge.head()

这将返回图 11

额外信息

根据输入的数据,pd.merge()允许我们进行各种类型的连接,例如一对一多对一多对多:

一对一 —一个数据帧中的每一行都使用“键”列与另一个数据帧中的一行相关。

一对多 —一个数据帧中的每一行都使用“键”列链接到另一个数据帧中的一行或多行。

多对多 —一个数据帧中的一行或多行使用“键”列与另一个数据帧中的一行或多行相关。

串联

我们可以认为串联是沿着一个轴将我们的数据集粘合在一起——或者是行轴或者是列轴pd.concat()允许我们做非常简单的连接,因此pd.merge()是必要的。

注意:[**concat()**](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.concat.html#pandas.concat)(因此也是**append()**)制作了数据的完整副本,不断地重用这个函数会对性能产生重大影响。如果需要在几个数据集上使用该操作,请使用列表理解。—来源 Pandas 文档。

图 12:连接的可视化。

pd.concat()的默认行为是保留两个轴数据的外部连接。但是,通过调整join参数,您可以修改函数来执行内部连接,这可能会导致一些数据丢失——只有轴标签匹配的地方才会保留行和列数据。

*# Gluing dataframes row-wise* 
row_glue= pd.concat([bill, tip], axis=0, sort=**False**)
row_glue.head(8)

图 13:行连接

*# Gluing dataframes column-wise* col_glue= pd.concat([bill, tip], axis=1, sort=**False**)
col_glue.head()

图 14:列连接

我们还可以通过向keys传递一个序列来添加一个指示器,指示每个连接开始的位置。

*# Adding an indicator* 
indicator_glue = pd.concat([bill, tip], axis=0, sort=**False**, keys=["df1", "df2"])
indicator_glue

图 15:添加了一个指示器来标识 concat 数据的来源。

包裹

Pandas 有许多用于组合数据的有用技术,在我看来,这些技术允许你将 Pandas 框架变成你自己的,正如我所做的那样,我只选择使用 2 个顶级函数来组合数据,以完成我所有的组合操作。

感谢您花时间阅读这个故事。如果你喜欢它,你可以在 PyTrix 系列中找到更多类似的文章。

[## Pytrix 系列-走向数据科学

阅读《走向数据科学》中关于 Pytrix 系列的文章。共享概念、想法和代码的媒体出版物。

towardsdatascience.com](https://towardsdatascience.com/tagged/pytrix-series)

如果您想亲自联系我,我是 LinkedIn 上最活跃的用户,我会非常乐意与您联系!

[## Kurtis Pykes -人工智能作家-走向数据科学| LinkedIn

在世界上最大的职业社区 LinkedIn 上查看 Kurtis Pykes 的个人资料。Kurtis 有一个工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/kurtispykes/)

你应该知道的提高数据分析速度的技巧

原文:https://towardsdatascience.com/pandas-concat-tricks-you-should-know-to-speed-up-your-data-analysis-cd3d4fdfe6dd?source=collection_archive---------1-----------------------

你应该知道的一些最有用的熊猫把戏

图片来自 Pixabay 的 GraphicMama-team

Pandas 提供了各种内置函数来轻松组合数据帧。其中,concat()函数看起来使用起来相当简单,但仍有许多技巧你应该知道,以加快你的数据分析。

在这篇文章中,你将学习熊猫concat()处理以下常见问题的技巧:

  1. 处理索引和轴
  2. 避免重复索引
  3. 使用keysnames选项添加分层索引
  4. 列匹配和排序
  5. 从一堆 CSV 文件中加载和连接数据集

源代码请查看我的 Github repo 。

1.处理索引和轴

假设我们有两个关于考试成绩的数据集。

df1 = pd.DataFrame({'name': ['A', 'B', 'C', 'D'],'math': [60,89,82,70],'physics': [66,95,83,66],'chemistry': [61,91,77,70]
})df2 = pd.DataFrame({'name': ['E', 'F', 'G', 'H'],'math': [66,95,83,66],'physics': [60,89,82,70],'chemistry': [90,81,78,90]
})

concat()最简单的连接是传递一系列数据帧,例如[df1, df2]。默认情况下,它沿着轴0垂直连接,并保留所有现有的索引。

pd.concat(**[df1, df2]**)

默认情况下,df1 和 df2 的索引都会保留

如果您希望串联忽略现有的索引,您可以设置参数ignore_index=True。然后,产生的数据帧索引将用0、…、n-1标记。

pd.concat([df1, df2], **ignore_index=True**)

pd.concat([df1, df2], ignore_index=True)的输出

要沿轴1水平连接数据帧,可以设置参数axis=1

pd.concat([df1, df2], **axis=1**)

pd.concat([df1, df2], axis=1)的输出

2.避免重复索引

现在,我们知道concat()函数保留了索引。如果您想验证pd.concat()结果中的索引没有重叠,您可以设置参数verify_integrity=True。设置为True时,如果有重复的索引,将引发异常。

try:pd.concat([df1,df2], **verify_integrity=True**)
except ValueError as e:print('ValueError', e)ValueError: Indexes have overlapping values: Int64Index([0, 1, 2, 3], dtype='int64')

3.使用keysnames选项添加分层索引

增加一个层次索引(也叫多级索引)对于更复杂的数据分析还是挺有用的。在这种情况下,我们分别为df1df2增加指标第一年第二年。为此,我们可以简单地指定keys参数。

res = pd.concat([df1, df2], **keys=['Year 1','Year 2']**)
res

并访问一组特定的值,例如, Year 1 :

res.**loc['Year 1']**

此外,参数names可用于为产生的分层索引添加名称。例如:将 name Class 添加到我们刚刚创建的最外层索引中。

pd.concat([df1, df2], keys=['Year 1', 'Year 2'],**names=['Class', None],**
)

要重置索引并将其转换为数据列,可以使用reset_index()

pd.concat([df1, df2], keys=['Year 1', 'Year 2'],names=['Class', None],
).**reset_index(level=0)** **# reset_index(level='Class')**

重置类别索引

4.列匹配和排序

concat()函数能够以不同的顺序连接数据帧和列。默认情况下,结果数据帧将与第一个数据帧具有相同的排序。比如下面这个例子,和df1的顺序一样。

如果您希望得到的数据帧按字母顺序排序,您可以设置参数sort=True

pd.concat([df1, df2], **sort=True**)

按列名排序

如果您喜欢自定义排序,以下是如何进行的:

**custom_sort** = ['math', 'chemistry', 'physics', 'name']
res = pd.concat([df1, df2])
**res[custom_sort]**

自定义排序

5.从一堆 CSV 文件中加载和连接数据集

假设我们需要从一堆 CSV 文件中加载和连接数据集。这是一个使用 for 循环的解决方案。

# Bad
import pathlib2 as pl2
ps = pl2.Path('data/sp3')res = None
**for p in ps.glob('*.csv'):**if res is None:res = pd.read_csv(p)else:res = **pd.concat([res, pd.read_csv(p)])**

这当然有用。但是pd.concat()在每次 for 循环迭代中都会被调用。我们可以使用列表理解有效地解决这个问题。

import pathlib2 as pl2
ps = pl2.Path('data/sp3')dfs = (**pd.read_csv(p, encoding='utf8') for p in ps.glob('*.csv')**
)res = **pd.concat(dfs)**
res

一行代码读取所有 CSV 文件并生成一个数据帧列表dfs。然后,我们只需要调用一次pd.concat(dfs)就可以得到相同的结果。

如果你用%%timeit计算两次执行的时间,你可能会发现列表理解解决方案节省了一半的时间。

# for-loop solution
**298 ms ± 11.8 ms per loop** (mean ± std. dev. of 7 runs, 1 loop each)# list comprehension solution
**153 ms ± 6 ms per** loop (mean ± std. dev. of 7 runs, 1 loop each)

列表理解节省时间和代码。与使用循环相比,这是一种简单的生成列表的方法。

好了

感谢阅读。

源代码请查看笔记本。

如果你对机器学习的实用方面感兴趣,请继续关注。

你可能会对我的其他一些熊猫文章感兴趣:

  • 如何对熊猫数据帧进行自定义排序
  • 何时使用熊猫变换()函数
  • 使用熊猫方法链接提高代码可读性
  • 在 Pandas 数据帧中处理日期时间
  • 处理熊猫中缺失的值
  • 熊猫阅读 _csv()你应该知道的招数
  • 用 Pandas read_csv()解析日期列应该知道的 4 个技巧

更多可以从我的 Github 中找到

Pandas 数据操作函数:apply()、map()和 applymap()

原文:https://towardsdatascience.com/pandas-data-manipulation-functions-7b3519fc1370?source=collection_archive---------20-----------------------

以及如何在熊猫身上正确使用它们…

图片来自 Pixabay 的 Couleur

一旦你开始使用 pandas,你会注意到为了处理数据,你需要对你的数据集做一些转换。几乎从来没有这样的情况,您加载数据集,并可以继续使用它的原始形式。您可能需要这样做有几个原因,例如:

改变单位(例如,数据集以千克为单位,而您需要以磅为单位)

做一些数学变换(对数、根等)

小写或大写字符串,

还有更多…

本文将解释如何使用 apply()、map()和 applymap()来实现它,以及何时使用其中一个而不使用另一个。

数列上的算术运算

在深入研究 apply()、map()和 applymap()之前,需要注意的是,一些简单的基本算术运算可以在不使用上述任何函数的情况下完成。这些是:

  • 添加
  • 减法
  • 增加
  • 或者以上的任意组合

让我们加载 Iris 数据集并查看一些示例:

from sklearn import datasets
import pandas as pdiris_data = datasets.load_iris()
df_iris = pd.DataFrame(iris_data.data,columns=iris_data.feature_names)
df_iris['target'] = pd.Series(iris_data.target)
df_iris.head()

做基本的算术运算是非常容易的。如果我们想要计算萼片长度与萼片宽度的比率,您只需将一列除以另一列:

df_iris['sepal_width_sepal_length_ratio'] = df_iris['sepal length (cm)'] / df_iris['sepal width (cm)']df_iris.head()

正如您所看到的,我们添加了一个新列,这是这个基本算术运算的结果。但是,如果你想使用更复杂的操作,如日志,地板,立方体等,会发生什么呢?

这就是 apply(),map()和 applymap()成为你的朋友的时候。

对系列应用()

让我们开始看看如何在 Series 对象上使用 apply()。我们将假装对记录萼片长度感兴趣。用 apply()很容易做到。我们只需要传递一个参数,一个我们希望应用于系列中每个元素的可调用函数。在我们的例子中,这是 math.log:

import math
df_iris['sepal_length_log'] = df_iris['sepal length (cm)'].apply(math.log)
df_iris.head()

如您所见,我们已经成功创建了一个名为 sepal_length_log 的新列,该日志应用于每个 sepal length 条目。

我们现在可以说明 apply()如何处理数据框,这是一个更复杂的例子。

JESHOOTS.COM在 Unsplash 上的照片

在数据帧上应用()

在 DataFrame 上使用的 Apply 函数与在 Series 上使用的 apply 函数略有不同。apply 函数应用于整行或整列,您需要指定轴。它再次将函数的可调用性作为参数。它最常见的用法是发送一整行作为函数的参数。

让我们看一些例子:

df_iris['all_dimensions'] = df_iris.drop('target', axis=1).apply(sum, axis=1)
df_iris.head()

在上例中,我们使用 apply()创建了*‘all _ dimensions*’列。为此,我删除了一个“目标”列,并使用 sum()函数对每行的所有其他列值求和。注意,我必须使用 axis=1 作为参数,以便将函数应用于每一行。

上面的用法可能不是最有用的,但是 apply 的强大之处在于定义你自己的函数。让我们在这里说明这一点。

假设您只想将给定的整行 sepal 数据相加。你可以这样定义你的函数:

def sepal_sum(row):return row['sepal length (cm)'] + row['sepal width (cm)']

现在,您可以使用 apply()将函数应用于每一行,如下所示:

df_iris['sepal_dimensions'] = df_iris.drop('target', axis=1).apply(sepal_sum, axis=1)
df_iris.head()

那很有用!当您愿意使用自己的更复杂的函数时,它会变得更加有用。

applymap()

在 DataFrame 上使用 apply()时,函数参数会变成整行或一列,具体取决于您定义的轴。但是,如果您想对数据框的每个元素应用某种函数,而不是对每一行或每一列应用某种函数,该怎么办呢?这就是 applymap()变得有用的时候。

假设有人犯了一个错误,你想在你的数据中的每一个条目上加 1,因为你已经发现这是一个测量中的一致错误。让我们从定义一个助手函数开始:

def add_one(item):return item + 1

让我们使用 applymap()将它应用于原始 iris 数据帧的每个元素,不包括目标列。

df_iris.drop('target', axis=1).applymap(add_one).head()

现在,如果您将此输出与原始输出进行比较,您会注意到每个条目都添加了一个。它显示了 applymap 的强大。

[## 当你开始与图书馆合作时,7 个实用的熊猫提示

解释一些乍一看不那么明显的东西…

towardsdatascience.com](/7-practical-pandas-tips-when-you-start-working-with-the-library-e4a9205eb443)

地图()

Map()函数只能在 Series 对象上使用,其工作方式与在 Series 上的 apply()相同。让我们将它与我们之前用来演示 apply()和 series 的日志示例一起使用。唯一的变化是在代码中我们交换应用到 map:

import math
df_iris['sepal_length_log'] = df_iris['sepal length (cm)'].map(math.log)
df_iris.head()

即使应用于序列,map 和 apply 之间也有区别。不同之处在于,在处理 series 时,apply 只能将一个可调用的函数作为参数。另一方面,Map()也可以接受一个集合(如字典),并根据映射应用它来更改序列中的值。让我们看一个例子:

df_iris.target = df_iris.target.map({0: 'species1', 1: 'species2'})
df_iris.head()

正如您所看到的,我们在这里使用了一个字典来将 0 和 1 相应地转换为' species1' 和' species2'

应用(),应用地图()和地图()摘要

这里总结一下最重要的区别。

Apply() 在数据帧的行/列基础上工作,或者在序列上应用时在元素上工作。

Applymap() 处理数据帧上的单个元素。

Map() 类似于 apply on Series,但它不仅可以接受可作为参数调用的函数,还可以接受字典之类的集合。

它们都非常有用,毫无疑问,掌握它们的用法会让你成为一名优秀的数据科学家。

我希望你喜欢这篇文章,并在今天学到一些新东西!

最初发布于 aboutdatablog.com: 熊猫数据操作函数:apply()、map()和 applymap() 、2020 年 4 月 8 日。

PS:我正在aboutdatablog.com上撰写深入浅出地解释基本数据科学概念的文章。 如果你喜欢这篇文章,还有一些其他的你可能会喜欢:

[## 对熊猫中的数据框进行排序

如何快速有效地排序数据帧

towardsdatascience.com](/sorting-data-frames-in-pandas-a5a3af6f346a) [## Jupyter 笔记本自动完成

数据科学家的最佳生产力工具,如果您还没有使用它,您应该使用它…

towardsdatascience.com](/jupyter-notebook-autocompletion-f291008c66c)

熊猫数据框架基础

原文:https://towardsdatascience.com/pandas-dataframe-basics-3c16eb35c4f3?source=collection_archive---------27-----------------------

开始使用这种非常有用的数据结构

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

在使用 Python 处理和分析数据时,Pandas 通常是数据科学家、分析师和工程师的默认选择。使用该库时使用的基本数据结构是 DataFrame。Pandas DataFrame 是由行和列数据组成的二维结构,与 Excel 电子表格或 SQL 数据库表没有什么不同。

一旦数据在这个数据结构中可用,您就可以执行各种操作来准备您的数据进行分析。在下面的文章中,我将向你介绍一些使用熊猫数据框架的基本概念。

创建数据框架

[pandas.DataFrame()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html)函数可用于将序列、数组、常量或列表形式的数据转换成数据帧。

下面的代码接受一个整数列表,并将它们转换成熊猫数据帧。我们传入一个列名列表,并使用pandas.head()函数显示前几行数据。

作者图片

导入数据

在本教程的剩余部分,我们将使用来自 UCI 机器学习知识库的开源数据集。该数据集包括一个成年人的许多特征,如年龄、教育水平和婚姻状况,以及一个表明他们年收入是否超过 5 万美元的目标。

我们可以使用[pandas.reas_csv()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html)函数直接从 URL 下载这个数据集。这个函数以熊猫数据帧的形式返回数据。

Pandas 支持多种导入数据的方法,包括:

  • pandas.read_excel()从 Excel 电子表格中读取。
  • pandas.read_sql()从 SQL 表中读取。
  • 来自一个带pandas.read_json的 JSON 文件。

添加新的列和行

需要向数据帧中添加新列以方便对数据的进一步分析是很常见的。有很多方法可以让你做到这一点。

例如,您可能希望根据条件添加新列。在下面的代码中,我们使用numpy.where()函数创建一个名为“兼职时间”的列,如果“每周小时数”小于 35,则该列的值为 1。我还调用了pandas.value_counts()来快速查看这个新列中每个值的成人数量。

作者图片

在我们使用的数据集中,有一列包含每个人的年龄。更好地分析这种数据类型的常用方法是将年龄分组或分类。我们可以使用pandas.cut()函数创建一个新的列来完成这项工作。我已经使用 pandas 绘图功能结合value_counts()创建了一个简单的分布可视化表示。

作者图片

索引和选择数据

在数据分析期间,通常执行的任务是从数据集中选择行和列的子集。Pandas 提供了许多方法来执行这种类型的操作。

如上所示,我们可以根据条件选择数据子集。假设我们想要选择年龄超过 65 岁的人所在的所有行和列。我们可以使用下面的代码做到这一点。

熊猫数据帧被索引,因此也可以根据索引选择数据。您可以使用索引来选择数据,或者通过标签(在这种情况下,您将使用DataFrame.loc()函数)或者通过基于整数的位置(使用DataFrame.iloc())。

以下代码选择标签为“occupation”的列的所有行。

这个代码片段使用列的整数位置执行完全相同的操作。

清理数据

真实世界的数据通常包含需要清除的缺失值或错误值。Pandas 有清除所有数据类型(包括整数、浮点数和对象)中缺失数据的方法。

为了用合适的值填充缺失的值,我们可以使用DataFrame.fillna()。在 fill 参数中,我们可以指定一个值,比如 0,或者指定一个字典,为每一行和/或每一列指定不同的值。

或者,我们可以选择使用DatFrame.dropna()删除包含缺失值的行。

导出数据

一旦你完成了你的数据帧,你可以把它导出回一个文件或数据库。Pandas 支持多种数据导出方法,包括:

  • pandas.to_csv()导出到 CSV 文件。
  • 使用pandas.to_excel()导出到 Excel 电子表格。
  • pandas.to_sql()写回 SQL 数据库。

熊猫图书馆包含大量有用的数据分析功能和工具。DataFrame 不仅为组织数据提供了一种清晰有序的方法,还为您提供了这些丰富的数据分析工具。本教程提供了基本数据框架功能的简单介绍,但是一旦数据以这种结构组织起来,就有更多的使用范围。如果你想更深入地探索我在这篇文章中概述的一些功能,我邀请你看看我以前的一些熊猫教程。

[## 关于熊猫你不知道的 10 件事

直到现在…

towardsdatascience.com](/10-things-you-didnt-know-about-pandas-d20f06d1bf6b) [## 熊猫里的情节越来越漂亮了

创建丰富的可视化和仪表板与熊猫绘图后端为 Plotly 和 Bokeh

towardsdatascience.com](/plotting-in-pandas-just-got-prettier-289d0e0fe5c0) [## 熊猫绘图 5 分钟指南

了解如何使用这个流行的 python 工具快速可视化数据

towardsdatascience.com](/5-minute-guide-to-plotting-with-pandas-e8c0f40a1df4)

感谢阅读!

我每月都会发一份简讯,如果你想加入,请点击此链接注册。期待成为您学习旅程的一部分!

熊猫数据帧按连续的特定值分组

原文:https://towardsdatascience.com/pandas-dataframe-group-by-consecutive-certain-values-a6ed8e5d8cc?source=collection_archive---------7-----------------------

照片由 geralt 在 Pixabay 上拍摄

Python 编程技巧

按任意行中出现的连续特定值对数据帧进行分组

我们通常希望通过连续的值来分割熊猫数据帧。然而,在任何情况下处理连续值几乎总是不容易的,比如 SQL,Pandas 也是如此。

标准 SQL 提供了一堆窗口函数来促进这种操作,但是在 Pandas 中没有太多的窗口函数。幸运的是,Python 中有许多变通方法,有时甚至比经典的窗口函数更简单。

在本文中,我将演示如何按照任意时间出现的某些值对熊猫数据帧进行分组。

问题定义

由 geralt 在 Pixabay 上拍摄的照片

如果您对这个标题有些困惑,下面的示例数据会让您明白。让我们首先创建示例数据帧。

df = pd.DataFrame({'item':['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M'], 'value':[12, 3, 5, 0, 0, 0, 23, 4, 2, 0, 0, 12, 0]
})

在本例中,我们希望为任意数量的连续值 0 分割数据帧。红色方块表示预计将从该原始数据帧中分离出三个数据段。

直觉

图片由 geralt 在 Pixabay 拍摄

我们在这里尝试做的事情通常有两个:

  1. 用具有value == 0的行过滤数据帧。
  2. 如果这些行不连续,请将它们分开。换句话说,至少有一行有value != 0

第一步很容易,但第二步显然不容易。在对解决方案进行编码之前,让我们先看看直观的步骤。

  1. 用所有布尔值创建一个“遮罩”系列。True若为value == 0,否则为False
  2. 使用掩码系列过滤数据帧。所以,我们有了所有带value == 0的行。
  3. 反转遮罩系列,因此True变为False,反之亦然。
  4. 对反转的掩码系列执行累积求和。
  5. 累积和数列可以用来分组,达到我们想要的。

重要的是要澄清,如果我们在 Python 中累加布尔值,True将被视为1,而False将被视为0

我知道,可能还是会让人困惑。让我们来看看下面的数据框架,它只是为了这种直觉而创建的,并不作为解决方案的一部分。

# This is not part of the solution, just for demo purposes
df_tmp = df
df_tmp['mask'] = mask
df_tmp['inversed_mask'] = ~mask
df_tmp['inversed_mask_cumsum'] = (~mask).cumsum()

绿色矩形显示了我们期望获得的预期行组。

那么,为什么我们需要在这里对反转的掩码列执行cumsum()

  1. 对于任何非零值,反转的掩码将具有True (1),对于任何零,反转的掩码将具有False (0)
  2. 当我们对这个反转的掩码列应用cumsum()时,连续0的结果将保持不变,而如果不是0,累积和将使值增加。

解决办法

奇莫诺在 Pixabay 上的照片

直觉过后,你可能会觉得这并不容易。然而,当你看到解决方案时,你可能会嘲笑它是多么容易。

df[df['value'] == 0].groupby((df['value'] != 0).cumsum())

对,就是这样。

我们可以验证这些组是否正确。

for k, v in df[df['value'] == 0].groupby((df['value'] != 0).cumsum()):print(f'[group {k}]')print(v)print('\n')

这正是我们所期待的:)

摘要

照片由 janjf93 在 Pixabay 上拍摄

事实上,我不会说熊猫提供了许多有用的窗口功能。但是,Python 中的 Pandas 是典型的不像 SQL 的“编程语言”。因此,它提供了更多的可能性,有时甚至能以更简单的方式解决问题。

[## 通过我的推荐链接加入 Medium 克里斯托弗·陶

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

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

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

熊猫数据帧按连续的相同值分组

原文:https://towardsdatascience.com/pandas-dataframe-group-by-consecutive-same-values-128913875dba?source=collection_archive---------8-----------------------

照片由 MichaelGaida 在 Pixabay 上拍摄

Python 编程技巧

按重复多次的连续相同值对熊猫数据帧进行分组

我们通常希望通过连续的值来分割熊猫数据帧。然而,在任何情况下处理连续值几乎总是不容易的,比如 SQL,Pandas 也是如此。此外,标准 SQL 提供了一堆窗口函数来促进这种操作,但是在 Pandas 中没有太多的窗口函数。幸运的是,Python 中有许多变通方法,有时甚至比经典的窗口函数更简单。

在本文中,我将演示如何通过重复一次或多次的连续相同值对 Pandas 数据帧进行分组。

问题定义

照片由Pixabay上的银莲花 123拍摄

如果您仍然不太确定我们要解决的问题是什么,请不要担心,您将通过如下生成的示例数据了解这一点:

df = pd.DataFrame({'item':['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M'], 'v':[1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 8, 8, 9]
})

在截图中,绿线划分了我们预期的组。

在这个例子中,对这些值进行分组实际上非常容易。就简单groupby('v')

然而,它实际上是假设值v必须单调递增。

如果值列不是单调递增的怎么办?

df = pd.DataFrame({'item':['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N'], 'v':[1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 8, 8, 9, 3]
})

在这个新示例中,我们再次添加了第 13 行,它的值为v == 3。如果我们单纯的groupby('v'),第 13 排会和 2、3、4 排放在同一个组,这不是我们想要的。

换句话说,第 13 行应该在一个单独的组中,因为它不是连续的。

直觉

奇莫诺在 Pixabay 上的照片

基本思想是创建这样一个列,它可以根据。对于连续的原始值,它必须具有相同的值,但是当原始值改变时,它必须具有不同的值。我们可以用cumsum()。以下是直观的步骤。

  1. 创建一个新列,将原始值下移一行
  2. 将移位值与原始值进行比较。如果相等,则为真,否则为假
  3. 在布尔列上使用cumsum(),得到的列可以用于分组

这是一个仅为直观目的而创建的示例数据帧。

为什么有效?如果你关注每一组:

  • shifted_not_equal_to_original的第一个布尔值为True,其余为False(如果该组有多行)。因此,cumsum()函数将使每组的第一行与前一组的最后一行有所不同。
  • 布尔值为True ,因为如果前一行值不同于当前行值,则移位后的值不同于原始值。另一方面,从这个连续条纹的第二行开始,它将是False,因为该值等于它的前一行。

解决办法

照片由 rubylia 在 Pixabay 上拍摄

我知道直觉看起来很复杂,但是一旦你理解了这些,使用这种方法就很容易了,如下所示。

df.groupby((df['v'].shift() != df['v']).cumsum())

让我们验证这些组:

for k, v in df.groupby((df['v'].shift() != df['v']).cumsum()):print(f'[group {k}]')print(v)

非常重要的是,第 13 排与第 2、3、4 排分开分组,这正是我们所期待的。

因此,这种方法将能够对连续的值进行分组,而不管这些值后来是否重复,只要它不是连续的,就会创建另一个组。

摘要

由自由照片在 Pixabay 上拍摄的照片

事实上,我不会说熊猫提供了许多有用的窗口功能。但是,Python 中的 Pandas 是典型的不像 SQL 的“编程语言”。因此,它提供了更多的可能性,有时甚至能以更简单的方式解决问题。

[## 通过我的推荐链接加入 Medium 克里斯托弗·陶

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

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

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

熊猫日期范围函数详细信息

原文:https://towardsdatascience.com/pandas-date-range-function-details-fc1bd91b80a0?source=collection_archive---------56-----------------------

考虑不同条件生成一系列日期

来源:王思然·哈德森

时间序列数据是以固定或恒定的时间间隔收集的数据集。时间序列数据用于跟踪长期预测,观察时间相关趋势或季节性趋势。这非常有用,通常用于金融机构、零售企业、房地产和许多其他类型的企业。但是如果你有数据但是没有记录日期呢?今年需要用去年的数据生成实验报告怎么办?或者,你可能需要在本季度使用上季度的数据。有时它是研究、分析或预测所必需的。

生成一系列日期

幸运的是熊猫有一个名为日期范围的函数来生成一系列日期或时间。我们将看到如何利用它来解决我们在工作中可能遇到的一些问题。在这里,我们将解决几个问题。

  1. 先说最简单的。以一天的频率生成一系列日期。
import pandas as pd
pd.date_range(start = '1/1/2020', end='1/15/2020')#Output:
DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05', '2020-01-06', '2020-01-07', '2020-01-08',                '2020-01-09', '2020-01-10', '2020-01-11', '2020-01-12',                '2020-01-13', '2020-01-14', '2020-01-15'],               dtype='datetime64[ns]', freq='D')

2。生成一系列间隔两天的日期

pd.date_range('1/1/2020', '1/15/2020', freq='2D')#Output:
DatetimeIndex(['2020-01-01', '2020-01-03', '2020-01-05', '2020-01-07', '2020-01-09', '2020-01-11', '2020-01-13', '2020-01-15'],               dtype='datetime64[ns]', freq='2D')

如果你注意到,我们不需要一直提到开始和结束。默认情况下,第一个日期作为开始日期,第二个日期作为结束日期。

3。制作一个只有工作日的时间序列

pd.date_range('1/1/2020', '1/15/2020', freq='B')#Output:
DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-06', '2020-01-07', '2020-01-08', '2020-01-09', '2020-01-10',                '2020-01-13', '2020-01-14', '2020-01-15'],               dtype='datetime64[ns]', freq='B')

在这里,“频率= 'B '表示工作日。

4.如果我们有开始日期,没有结束日期,该怎么办。在这种情况下,我们可以只输入一个句点,这意味着我们需要的日期或次数。

pd.date_range('1/1/2020', periods = 9, freq='B')#Output:
DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-06', '2020-01-07', '2020-01-08', '2020-01-09', '2020-01-10',                '2020-01-13'],               dtype='datetime64[ns]', freq='B')

5。如果我们有一个结束日期和一个周期(或者我们需要多少个日期),

pd.date_range(end='1/1/2020', periods = 5)#Output:
DatetimeIndex(['2019-12-28', '2019-12-29', '2019-12-30', '2019-12-31', '2020-01-01'],               dtype='datetime64[ns]', freq='D')

如果我们不指定频率,date_range 函数将使用“freq='D '”。

6.频率不一定要以天数或工作日为单位。它可以是月、小时、分钟、秒和许多其他频率。让我们用一个 3M 的频率。

pd.date_range('1/1/2020', periods = 5, freq='3M')#Output:
DatetimeIndex(['2020-01-31', '2020-04-30', '2020-07-31', '2020-10-31', '2021-01-31'],               dtype='datetime64[ns]', freq='3M')

以下是所有频率的完整列表:

7。找出每个月的业务月末日期。

使用“BM”作为上面频率表中的频率。提供开始日期和“周期”值。

pd.DataFrame(pd.date_range('1/1/2018', periods=12, freq='BM'), columns=['Date'])

这里是 2018 年每个月的最后一个工作日。

7。你的客户可能在不同的时区,比如在非洲:

pd.date_range('1/11/2019', periods=5, tz='Africa/Abidjan', freq='3H')#Output: 
DatetimeIndex(['2019-01-11 00:00:00+00:00', '2019-01-11 03:00:00+00:00', '2019-01-11 06:00:00+00:00', '2019-01-11 09:00:00+00:00',  '2019-01-11 12:00:00+00:00'],               dtype='datetime64[ns, Africa/Abidjan]', freq='3H')

这里我使用的是每小时一次的频率。点击所有时区的链接。

下面是熊猫 date_range 函数的视频:

我希望它有帮助。

熊猫显示选项

原文:https://towardsdatascience.com/pandas-display-options-8b77ab25d7fe?source=collection_archive---------41-----------------------

当默认设置不符合您的要求时

马特·派克在 Unsplash 上的照片

Pandas 是一个非常强大的 Python 数据分析库,可以加速项目的预处理步骤。Pandas 的核心数据结构是 DataFrame ,它用带有标签的行和列的表格形式表示数据。Pandas 为数据帧提供了许多显示选项。默认设置在大多数情况下都适用,但您可能需要根据数据集的特征来调整它们。通过广泛的设置选项,pandas 允许创建一个定制的显示偏好。

显示选项可以用两个函数来处理:

  • get_option:显示设置的选项
  • set_option:允许改变选项

让我们导入一个示例数据帧,并通过示例来完成:

import pandas as pd
import numpy as npdf = pd.read_csv("/content/Telco-Customer-Churn.csv")df.shape
(7043, 21)df.head()

数据帧有 21 列,但只显示了 10 列。中间的用点表示。我们可以很容易地调整它,但让我们首先了解显示列的选项:

pd.get_option("display.max_columns")
10

不出所料,现在是 10 点。我们可以使用 set_option 函数和指示要显示多少列的类似语法来调整它:

pd.set_option("display.max_columns", 25)df.head()

现在所有的列都显示出来了。它们不适合屏幕,但我们可以使用底部的滚动条看到它们。

当我们拥有包含许多观察特征的宽数据框架时,此选项非常有用。

显示行也有类似的选项:

pd.get_option("display.max_rows")
60

因此,如果我们想要查看 100 行,我们可以类似地调整此设置:

pd.set_option("display.max_rows", 100)

还有一个调整列的显示宽度的选项。在某些情况下,数据集包含长字符串,这些字符串太长,无法使用默认设置显示。如果我们想查看完整的字符串,我们可以使用 max_colwidth 参数。让我们先来看看默认选项:

pd.get_option("display.max_colwidth")
50

因此,如果一个单元格包含的字符超过 50 个,我们就无法看到所有的字符。我创建了一个简单的数据框架来展示它在截断视图下的样子:

让我们增加宽度以查看完整的文本:

pd.set_option("display.max_colwidth", 150)

我们可能需要调整的另一个显示选项是浮点数的精度。默认值应该就可以了,但是可能会有一些极端的情况需要更高的精度:

pd.get_option("display.precision")
6

默认值为 6。让我们把它增加到 10。我们可能还想减少它,使它看起来更简单。

pd.set_option("display.precision", 10)

有更多的熊猫显示选项可以调整。我想强调一下你可能更经常需要的那些。如果你想看完整的列表,你可以随时访问熊猫文档。

如果你想了解更多关于熊猫的信息,这里有一个详细的熊猫帖子列表:

  • 完整的熊猫指南
  • 与熊猫的时间序列分析
  • 用熊猫处理缺失值
  • 熊猫——用这些简单的技巧节省内存
  • 重塑熊猫数据帧
  • 熊猫串操作—解释
  • 熊猫分组——解释
  • 如何和熊猫“读 _ CSV”

感谢您的阅读。如果您有任何反馈,请告诉我。

特定于熊猫数据类型的操作:访问器

原文:https://towardsdatascience.com/pandas-dtype-specific-operations-accessors-c749bafb30a4?source=collection_archive---------32-----------------------

举例说明。

蒂埃拉·马洛卡在 Unsplash 上拍摄的照片

注:除非另有说明,所有图片均由作者创作。

Pandas 是 Python 中一个广泛使用的数据分析和操作库。它提供了许多函数和方法来处理任何类型的数据。还有一些方法只适用于特定的数据类型。这些方法通过 4 个访问器来访问。

访问器扩展了 Pandas 的功能,并提供了特定的操作。例如,可以使用 dt 访问器从日期中提取月份。

在本帖中,我们将看到熊猫的 4 个访问器的各种操作,它们是:

  • Str:字符串数据类型
  • 分类数据类型
  • Dt:日期时间、时间增量、周期数据类型
  • 稀疏:稀疏数据类型

注意:我们将使用 Pandas 系列的示例,该系列也可以视为 DataFrame 列。

Str

Str 访问器提供了处理文本数据的方法。让我们首先创建一个包含文本单词的系列。

顾名思义,Split 根据指定的字符(默认为空格)拆分数据。然后,我们使用 explode 函数将每个分离的单词作为系列中的一个新项目。

猫是分裂的反义词。它将字符串串联成一系列。

upper 和 lower 方法分别将所有字符转换为大写和小写。

大写方法只将第一个字母转换成大写。

replace 方法可用于用另一个字符串替换整个或部分字符串。

len 方法返回一系列字符串的长度。

字符串访问器允许对字符串使用索引。例如,我们可以只选择前两个字符,如下所示:

我们也可以用 isalpha 方法检查是否所有字符都是字母顺序的。

如果至少有一个非字母字符,则返回 false。

Startswith 和 endswith 方法允许检查字符串是以特定字符开始还是结束。

我们还可以计算一个字符或一组字符在一个字符串中出现的次数。

lstrip 和 rstrip 方法可用于修剪字符串。例如,我们可以去掉 c 系列末尾的数字、空格和逗号。

Dt

Dt 访问器允许从日期时间数据中提取许多有用的属性。它还提供了操作方法。让我们首先创建一个简单的日期序列。

date_range 函数返回 datetimeindex。为了使用 dt 访问器,我们需要将其转换为一个序列。

我们可以通过简单地使用年、月和日属性从日期中提取年、月或日。

在某些情况下,我们可能需要日期的日历周。可以按如下方式完成:

还可以提取日期的星期几。从 0(周一)开始,一直到 6(周日)。

我们能够检查一个日期是一个月、一个季度还是一年的开始还是结束。让我们做一个例子来检查一个月的开始。季度和年度的语法类似。

Cat 是分类数据类型的访问器。对于分类数据,使用分类数据类型比使用对象数据类型更有效。这在内存和速度方面有很大的不同,尤其是当数据基数较低时(即,与观察值相比,类别数较低)。

让我们首先创建一个具有分类数据类型的序列。

我们可以检查类别。

也可以重命名类别。

使用类别数据类型时要记住的一件重要事情是,新值必须在现有类别中。

例如,ser 中的类别是 A、B 和 c。我们不能将一个项目更新到除这三个类别之外的类别。如果我们试图这样做,就会得到一个值错误。

为了解决这个问题,我们可以添加新的类别,即使还没有数据点属于该类别。

我们现在可以将一个数据点更新为 d 类。

稀疏

Pandas 的稀疏数据结构允许高效地存储稀疏数据。谈到稀疏性,我们倾向于认为数组主要由零组成。然而,稀疏也可能是由于其他值(例如 NaN)。稀疏数据结构意味着通过省略匹配特定值(例如 0,1,NaN)的数据点来压缩对象。

让我们坚持传统的大部分是零的情况。下面的 numpy 数组包含 20 个 1 和 9980 个 0。

让我们创建两个系列。一个具有稀疏数据类型,一个具有浮点数据类型。

在内存使用方面会有巨大的差异。

内存使用量减少了 200 多倍。

稀疏数据结构的数据类型有两个元素。第一个是实际存储的元素的数据类型。第二个显示了未存储的稀疏元素。

在有序的情况下,稀疏性是由于零,所以零实际上没有被存储。

稀疏存取器提供了检查稀疏数据结构属性的方法。npoints 方法返回非 fill_value 点(实际存储的点)的数量。fill_value 点是稀疏度的值。

稀疏数组包含 20 个 1,其余值为零。

fill_value 方法显示稀疏元素,density 返回非 fill_value 点与整个数组的比率。

最后,sp_values 方法返回一个只包含非 fill_value 点的数组。

我们已经讨论了与访问器相关的方法的重要部分。当然,还有更多的方法,但我认为这些是你在数据分析过程中会经常用到的方法。他们肯定会让你的事情变得更容易。

您可以随时访问访问器官方文档的 API 来查看方法的完整列表。

感谢您的阅读。如果您有任何反馈,请告诉我。

熊猫相当于 10 个有用的 SQL 查询

原文:https://towardsdatascience.com/pandas-equivalent-of-10-useful-sql-queries-f79428e60bd9?source=collection_archive---------0-----------------------

…或者是面向 SQL 开发人员的熊猫

图片由PublicDomainPictures@Pixabay提供

如果你不知道,pandas 是一个用于数据操作和分析的 python 库。特别是,它提供了数据结构和操作来操作数字表和时间序列。这个名字来源于术语“面板数据”,这是一个计量经济学术语,指的是包含同一个人在多个时间段的观察结果的数据集。

基本上,它是 python 中处理表格的一种方式。在熊猫中,数据表被称为。

如标题所示,在本文中,我将向您展示一些最有用的 SQL 查询的 pandas 等价物。这既可以作为那些已经知道 SQL 的人对 pandas 的介绍,也可以作为您可能需要的常见 pandas 操作的备忘单。

对于下面的例子,我将使用这个数据集,它包含了美国 YouTube 视频的趋势数据。它由 40949 行和 16 列组成:video_id、trending_date、title、channel_title、category_id、
publish_time、tags、views、likes、unless、comment_count、
thumbnail_link、comments_disabled、ratings_disabled、
video_error_or_removed、description。

import numpy as np
import pandas as pd# Reading the csv file into a DataFrame
df = pd.read_csv('USvideos.csv')

默认情况下,Pandas 操作不会修改您正在处理的数据框;它们只是返回其他数据框,您需要将这些数据框赋给一个变量,或者如果您想要保存更改,请使用参数 inplace=True。对于下面的大多数例子,我们不改变我们的原始数据框,我们只是显示返回的结果。

1.挑选

SELECT col1, col2, ... FROM table

SELECT 语句用于从表中选择数据列。

要在 pandas 中做同样的事情,我们只需在数据框上使用数组符号,并在方括号内传递一个包含您想要选择的列名的列表。

df[['video_id', 'title']]

同样的事情也可以用下面的语法来实现,这样以后翻译 WHERE 语句就更容易了:

df.loc[:, ['video_id', 'title']]

SELECT DISTINCT col1, col2, ... FROM table

SELECT DISTINCT 语句只返回表中唯一的行。

数据框中可能存在重复值。如果您只想获得不同的行(删除重复的行),那么调用.drop_duplicates()方法就很简单。根据该方法的名称判断,您可能认为它从初始数据框中移除了重复行,但它实际上是返回移除了重复行的新数据框。

df.loc[:, ['channel_title']].drop_duplicates()

SELECT TOP number col1, col2, ... FROM table

SELECT col1, col2, ... FROM table LIMIT number

SQL 中的 TOP 或 LIMIT 关键字用于限制从表顶部返回的行数。对于熊猫来说,用.head(number)方法很容易做到这一点。Pandas 也有从数据帧末尾开始显示行的.tail(number)方法。

df.loc[:, ['video_id', 'title']].head(5)

df.loc[:, ['video_id', 'title']].tail(5)

SQL 的 MIN()、MAX()、COUNT()、AVG()和 SUM()函数很容易翻译成 pandas:

SELECT MIN(col) FROM table

df.loc[:, ['views']].min()

SELECT MAX(col) FROM table

df.loc[:, ['views']].max()

SELECT COUNT(col) FROM table

df.loc[:, ['views']].count()

SELECT AVG(col) FROM table

df.loc[:, ['views']].mean()

SELECT SUM(col) FROM table

df.loc[:, ['views']].sum()

现在,如果我们想做这样的事情呢:
SELECT MAX(likes), MIN(dislikes) FROM table?我们需要采取更多的步骤:

new_df = df.loc[:, ['likes']].max().rename({'likes': 'MAX(likes)'})
new_df['MIN(dislikes)'] = df.loc[:, ['dislikes']].min().values[0]

2.在哪里

SELECT col1, col2, ... FROM table WHERE condition

WHERE 子句用于仅提取满足指定条件的行。

回想一下我们到目前为止用于选择列的语法:
df.loc[:, ['col1', 'col2']]
.loc的方括号内有两个参数;到目前为止,我们只使用了第二个选项,它用于指定您想要选择的列。猜猜第一个参数是什么?用于选择行。Pandas 数据帧期望一个行索引或布尔标志的列表,它根据这个列表提取我们需要的行。到目前为止,我们只使用了表示“返回所有行”的符号:。如果我们只想提取索引从 50 到 80 的行,我们可以在那个地方使用50:80

为了根据某种条件提取行,我们通常会传递一个由某种(矢量化)布尔运算返回的布尔标志数组。位置为 False 的行不会包含在结果中,只会返回位置为 True 的行。

使用等式和不等式运算符 =,<,< =,>,> =,!= 在条件是直截了当的。例如,要仅返回赞数> = 1000000 的行,我们可以使用:

df.loc[df['likes'] >= 1000000, ['video_id', 'title']]

请注意,我们之所以能做上面(df['likes'] >= 1000000)的事情,是因为 pandas 已经覆盖了> =操作符的默认行为,因此它将操作符应用于元素,并返回我们需要的形状(行数)的布尔数组。
但是操作符 and,or,not 不是这样工作的。所以,我们就用 & 代替**, | 代替~ 代替而不是。**

df.loc[(df['likes'] >= 1000000) & (df['dislikes'] <= 5000), ['video_id', 'title']].drop_duplicates()

SELECT col1, col2, ... FROM table WHERE colN IS NOT NULL

在 SQL 中,您可以使用IS NULLIS NOT NULL来获取包含/不包含空值的行。

如何检查熊猫中的空值?我们将使用熊猫包中的isnull(array-like)功能来实现。注意这不是数据框对象的方法,不要用df.isnull(...);而是做pd.isnull(df['column'])。所以要小心。

下面的示例返回 description 不为 null 的所有行。

SELECT col1, col2, ... FROM table WHERE colN LIKE pattern

LIKE 关键字可以在 WHERE 子句中用来测试列是否匹配某个模式。

在 pandas 中,我们可以使用 python 的本地 re 正则表达式模块来完成同样的事情,甚至更多,因为 python 的 re 模块允许测试一组更丰富的模式,而不是 SQL 之类的。

我们将创建一个函数like(x, pattern),其中 x 是一个类似数组的对象,pattern 是一个包含我们想要测试的模式的字符串。这个函数首先将模式编译成一个正则表达式对象,然后我们可以使用.fullmatch(val)方法根据我们的模式测试val的值。为了对 x 向量中的每个元素进行测试,我们将使用 numpy 的vectorize(func)函数为正则表达式匹配操作创建一个向量等价物。最后,我们将这个矢量化函数应用到我们的 x 输入向量。然后我们需要做的就是在.loc[]中传递like(df['column'], pattern)作为第一个参数。

import redef like(x, pattern):r = re.compile(pattern)vlike = np.vectorize(lambda val: bool(r.fullmatch(val)))return vlike(x)

例如,下面的代码返回所有描述中包含单词“math”的视频。

df_notnull = df.loc[~pd.isnull(df['description']), :]
df_notnull.loc[like(df_notnull['description'], '.* math .*'), ['video_id', 'title']].drop_duplicates()

3.以...排序

SELECT col1, col2, ... FROM table ORDER BY col1, col2 ASC|DESC

这个 SQL 关键字用于按升序或降序对结果进行排序。

将它翻译成 pandas 很简单,只需在数据帧上调用.sort_values(by=['col1', ...], ascending=True/False)方法。

df.loc[df['likes'] >= 2000000, ['video_id', 'title'] ].sort_values(by=['title'], ascending=True).drop_duplicates()

4.分组依据

SELECT col1, col2, ... FROM table GROUP BY colN

GROUP BY 语句对特定列中具有相同值的行进行分组。它通常与聚合函数(最小值、最大值、计数、总和、AVG)一起使用。

在 pandas 中,简单到调用.groupby(['col1', ...])方法,然后调用.min().max().count().sum.mean()方法之一。

df.loc[:, ['channel_title', 'views', 'likes', 'dislikes'] ].groupby(['channel_title']).sum()

5.拥有

SELECT col1, col2, ... FROM table GROUP BY colN HAVING condition

HAVING 关键字用于根据组级别的条件过滤结果。

在熊猫中,我们有.filter(func)方法,可以在groupby()调用之后调用。我们需要向该方法传递一个函数,该函数将一个组的数据帧作为参数,并返回一个布尔值,该值决定该组是否包含在结果中。
但是如果我们想在 pandas 中一次做更多的事情,例如,在列上应用聚合函数,并基于组级别的条件过滤结果,我们需要在更多的步骤中这样做。而在 SQL 中,我们只需要一个查询就可以做到。

在下面的例子中,我们希望按 channel_title 分组,只允许表中至少有 100 个视频的频道,并对的浏览量喜欢不喜欢应用平均函数。

在 SQL 中,这将是:

**SELECT** channel_title, AVG(views), AVG(likes), AVG(dislikes)
**FROM** videos_table
**GROUP** **BY** channel_title
**HAVING** **COUNT**(video_id) **>=** 100;

在熊猫身上:

g = df.groupby(['channel_title'])
g = g.filter(lambda x: x['video_id'].count() > 100)
g = g.loc[:, ['channel_title', 'views', 'likes', 'dislikes']]
g = g.groupby(['channel_title']).mean()

6.插入

INSERT INTO table (column1, column2, ...) VALUES (value1, value2, ...)

这个 SQL 语句用于在表中插入新行。

在 pandas 中,我们可以使用.append()方法在现有数据帧的末尾添加一个新的数据帧。我们将使用ignore_index=True从旧数据帧的最后一行开始继续索引。

new_row = pd.DataFrame({'video_id': ['EkZGBdY0vlg'],'channel_title': ['Professor Leonard'],'title': ['Calculus 3 Lecture 13.3: Partial Derivatives']})
df = df.append(new_row, ignore_index=True)

7.删除

DELETE FROM table WHERE condition

DELETE 语句用于根据某种条件从表中删除现有的行。

在 pandas 中,我们可以使用.drop()方法删除我们传入索引的行。与其他方法不同,这个方法不接受布尔数组作为输入。因此,我们必须将条件的输出转换为索引。我们可以通过np.where()功能来实现。

在下面的例子中,我们删除了所有包含 channel_title!= '3Blue1Brown'

df = df.drop(np.where(df['channel_title'] != '3Blue1Brown')[0])

8.改变

ALTER TABLE table ADD column

此 SQL 语句添加新列。

在熊猫身上,我们可以这样做:df['new_column'] = array-like

下面我们添加一个新列‘like _ ratio’:

df['like_ratio'] = df['likes'] / (df['likes'] + df['dislikes'])

ALTER TABLE table DROP COLUMN column

此 SQL 语句删除一列。

del df['column']我们在熊猫身上就是这么做的。

例如,删除“comments_disabled”列将是:

del df['comments_disabled']

9.更新

**UPDATE** table_name
**SET** column1 **=** value1, column2 **=** value2, ...
**WHERE** condition;

UPDATE 语句用于根据某些条件改变表中的值。

为了在 python 中做到这一点,我们可以使用 numpy 的where()函数。当我们用这个函数将一个布尔数组转换成索引数组时,我们在上面几行也看到了这个函数。这就是这个函数在只有一个参数的情况下所做的事情。这个函数可以接收 3 个相同大小的数组作为参数,第一个是布尔数组。让我们称它们为 c,x,y。它返回一个相同大小的数组,其中填充了以这种方式选择的来自 x 和 y 的元素:如果 c[i]为真,则选择 x[i]否则选择 y[i]。
要修改一个数据框列我们可以这样做:

df['column'] = np.where(condition, new_values, df['column'])

在下面的例子中,我们将赞数增加 100,其中 channel_title == 'Veritasium '。

这是之前的数据:

df.loc[df['channel_title'] == 'Veritasium', ['title', 'likes']]

将 Veritasium 频道的赞数增加 100:

df['likes'] = np.where(df['channel_title'] == 'Veritasium', df['likes']+100, df['likes'])

运行上述查询后:

10.加入

JOIN 子句用于根据两个或多个表之间的相关列来组合它们中的行。

为了展示连接的例子,我至少需要两个表,所以我将把目前使用的数据框分成两个更小的表。

df_titles = df.loc[:, ['video_id', 'title']].drop_duplicates()

df_stats = df.loc[:, ['video_id', 'views', 'likes', 'dislikes'] ].groupby('video_id').max()
# transform video_id from index to column
df_stats = df_stats.reset_index()

在 pandas 中进行连接很简单:数据帧有一个.join()方法,我们可以这样使用:
df1.join(df2.set_index('key_column'), on='key_column')

还有更多类型的联接:内部联接、完全联接、左联接和右联接。

  • 内部联接:返回在两个表中都有匹配值的行
  • 完全(外部)联接:返回在任一表中具有匹配值的行
  • LEFT JOIN:返回左侧表中的所有行,以及右侧表中匹配的行
  • 右连接:返回右表中的所有行,以及左表中匹配的行

图片来自 w3schools

要在 pandas 中指定您想要的连接类型,您可以使用.join()方法中的 how 参数。此参数可以是以下之一:“内部”、“外部”、“左侧”、“右侧”。

下面是“video_id”列上两个数据帧的内部连接示例。其他类型的连接以相同的方式完成,只需相应地更改“how”参数。

SQL 中的内部联接:

**SELECT** *
**FROM** df_titles
**INNER** **JOIN** df_stats
**ON** df_titles.video_id **=** df_stats.video_id;

熊猫的内心世界:

df_titles.join(df_stats.set_index('video_id'), on='video_id', how='inner')

这篇文章的笔记本可以在这里找到。

我希望这些信息对你有用,感谢你的阅读!

这篇文章也贴在我自己的网站这里。随便看看吧!

熊猫数据科学基础

原文:https://towardsdatascience.com/pandas-essentials-for-data-science-15378edef18b?source=collection_archive---------35-----------------------

数据导入和检查、缺失值、列和行操作等等

照片由马腾·范登赫维尔在 Unsplash 上拍摄

Python 是数据科学中的一种流行语言,当然,也是生产中最流行的机器学习语言。

然而,如果你看一下数据科学、分析和商业智能在各行各业和学术界的整体情况,你会发现 Python 有机会利用新的工具和技术成长。

作为一个例子,时间序列分析在 R 环境中取得了巨大的进展。这是因为它进入像fpp2这样的丰富库的门槛很低。Python 在时间序列的某些领域仍然很受欢迎,但在预测领域要达到与 T1 相当的水平还有很长的路要走。

首先,它需要越来越多对用 Python 做数据科学感兴趣的从业者。对于新手来说,最重要的是确保进入门槛低。

这篇文章的目的是谈论 Python pandas的实用程序来设置您的数据分析环境。这是为了展示学习少量命令就能开始更高级的建模。

熊猫是什么?

pandas是 Python 中一个功能强大、灵活易用的数据挖掘库。它最初是在一家财务管理公司开发的。任何熟悉金融行业的人都知道,金融行业的许多数据科学实际上是时间序列分析。

事实上,熊猫这个名字来源于 panel data ,是计量经济学中使用的一种特殊类型的时间序列数据。如果你对计量经济学及其在数据科学中的应用感兴趣,看看这个:

[## 数据科学家的计量经济学 101

数据科学家如何利用经济学家的工具箱

towardsdatascience.com](/econometrics-101-for-data-scientists-584f4f879c4f)

熊猫争夺数据

数据科学家花费大量时间(有人说是 80%)争论和准备数据进行分析。由于pandas是专门为满足分析管道的这一部分而设计的,如果你知道它是如何工作的,以及如何最好地利用它进行数据准备,剩下的就很容易了。

因此,这是一条让数据分析做好准备的分析管道——从基本分析到高级建模。

导入数据

第一件事当然是安装pandas库。

import pandas as pd

现在,您可以从各种来源导入数据。它可以是你电脑上的文件,网页上的文本,或者通过查询 SQL 数据库。

数据也有多种格式,如 csv、excel、json 等。

所以知道从哪里导入以及它是哪种格式将决定使用什么命令。这里有几个例子。

# improt a csv from the local machine or from the web
df = pd.read_csv("Your-Data-Path.csv")# importing an excel file from the computer
df = pd.read_excel("Your-Data-Path.xlsx")

数据检查

导入数据后,您需要检查一些东西,如数据结构、行数和列数、唯一值、NaN 值等。

# description of index, entries, columns, data types, memory info
df.info()# know the number of rows and columns
df.shape# check out first few rows
df.head()# if too many columns, list all of them
df.columns# number of unique values of a column
df["column_name"].nunique()# show all unique values of ONE column
df["column_name"].unique()# number of unique values in ALL columns altogether
df.columns.nunique()

缺少值

数据集中缺少值并不奇怪。首先,您需要检查是否有丢失的值:

# checking out number of missing values in each column
df.isnull().sum()# number of missing values as a percentage of total observations
df.isnull().sum()*100/len(df)

现在,一旦您发现有缺失值,您可以做一些事情—删除缺失值行、删除整个列、替换值—所有这些都取决于您的分析/建模需求。以下是一些基本命令:

# drop all rows containing null
df.dropna()# fill na values with strings
df.fillna("data missing")# fill na values with mean of columns
df.fillna(df.mean())

我写了一整篇关于处理缺失值的文章,如果你想看的话:

[## 处理数据科学项目中的缺失数据

如何不因丢失数据而丢失有价值的信息

towardsdatascience.com](/dealing-with-missing-data-in-data-science-projects-e8ac7a4efdff)

列操作

我所说的列操作是指几件事情中的一件——选择列、删除列、重命名、添加新列、排序等等。在高级分析中,您可能希望创建一个基于现有列计算的新列(例如,基于现有的“出生日期”列创建“年龄”)。

# select a column by name
df["column_name"]# select multiple columns by column name
df[["column_name1", "column_name2"]] # notice the double brackets# select first 3 columns based on column locations
df.iloc[:, 0:4]# select columns 1, 2, 5
df.iloc[:, [1, 2, 5]]# drop a column
df.drop("column_name", axis = 1)# create a list of all columns in a dataframe
df.columns.tolist()# rename a column
df.rename(columns = {"old_name": "new_name"})# create a new column by multiplying an old column by 2
df["new_column_name"] = df["existing_column"] * 2# sorting a column value in an ascending order
df.sort_values(by = "column_name", ascending = True)

行操作

一旦你处理好了列,接下来就是行。出于多种原因,您需要使用行,最明显的是过滤或切片数据。此外,您可能希望在数据框架中添加新的观察值或移除一些现有的观察值。以下是过滤数据所需的一些命令:

# select rows 3 to 10
df.iloc[3:10, ]# select 3 to 10 rows AND columns 2 to 4
df.iloc[3:10, 2:5]# take a random sample of 10 rows 
df.sample(10)# select rows with specific string
df[df["colum_name"].isin(["Batman"])]# conditional filtering: filter rows with >5 
df.query("column_name > 5")

特例:准备时间序列数据

时间序列是一种不同的对象,不像的任何数据框架。原始数据通常没有为时间序列分析进行格式化,因此pandas库将它们视为普通的数据帧,其中时间维度存储为字符串,而不是一个datetime对象。因此,您需要将普通的数据帧转换为时间序列对象。

# convert Date column to a datetime object
df["Date"] = pd.to_datetime(df["Date"])# set Date as the index
df = df.set_index("Date")# add new columns by splitting index
df["Year"] = df.idex.year
df["Month"] = df.index.month
df["Weekday"] = df.index.weekday_name

关于时间序列数据准备的更多信息,这里有一篇文章:

[## 为时间序列分析准备数据

一些简单的技巧和窍门来获得分析就绪的数据

towardsdatascience.com](/preparing-data-for-time-series-analysis-cd6f080e6836)

一锤定音

每个人都从不同的起点开始他们的数据科学之旅。然而,理解的程度和达到目标所需的时间有很大的不同,因为每个人采取不同的学习途径。如果有人遵循逻辑学习过程,使用 Python 学习数据争论的基础知识应该不难。在本文中,我用一些最常用的命令概述了逻辑顺序——数据导入、检查、缺失值、列操作、行操作。我希望这对您的数据科学之旅有用。

生物学家的熊猫

原文:https://towardsdatascience.com/pandas-for-biologists-f01c8a548b7c?source=collection_archive---------29-----------------------

为什么生命科学家要学习如何编码以及从哪里开始

照片由émile Perron在 Unsplash 拍摄

赶上那班火车!

学习如何编码对许多生命科学家来说仍然是令人生畏的。研究生和博士后普遍感到,他们的背景教育没有让他们为挑战做好准备。学习新的计算技能的时间似乎已经过去了。“他们误了火车”。

事实是,从零开始学习如何编码是非常耗时的,对于我们大多数在高度竞争的环境中工作的人来说,在生产和发布我们的工作的无尽压力下,这可能感觉像是我们在给定时间内进行的智力努力的一个弯路。我们有很多事要做。我们总是有很多事情要做。然而,大多数人没有理解的是,研究人员没有必要成为尖端的程序员,拥有构建网络内容或移动应用的敏锐能力。边际水平的编码技能将使大多数科学家有能力自动化重复的任务,操纵数据和图像,并增加他们在分享和展示他们的工作时的资源。此外,越来越明显的是,在不久的将来,仅使用电子表格和标准软件来跟踪和操作信息将变得不切实际。缺乏理解基本代码和编写自己定制的脚本来分析和优化实验的能力的科学家将很难跟上步伐。今天看来具有挑战性的妥协,从长远来看肯定会有回报。花在笔记本电脑上的时间可能比许多实验更有价值。编程专业知识将使我们成为更好的科学家,我们研究问题的答案将更快更有效地到来。

也许你错过了一班火车,但还有许多其他的火车要赶。这篇短文是我试图在下一篇文章中给你一点启发。

边做边学&熊猫

你可能还没注意到,我不是数据科学家。事实上,我是那种'*经典'*的实验生物化学家,在整个大学期间从未写过一行代码。学习如何编程的动力来自于我已经读了一半博士学位的时候。随着我的数据越积越多,我发现自己花了几个小时重复相同的分析协议,要么优化参数,要么用新数据填充我的模型。我意识到,标准软件和电子表格是一个脆弱的东西。因此,我决定投身到编程世界中去,以获得能让我自动完成工作中枯燥部分的技能。这让我接触到了 Python、,这是我目前博士旅程中的一个游戏改变者。我在任何类型的数据和图像分析方面都变得更加省时,从我的同龄人中脱颖而出,并增加了我在各种数据驱动领域的职业前景。

最初,我的主要斗争是认识到我所学的东西的价值。我花了很多空闲时间,却很少应用那些*【知识】*。学习曲线似乎非常陡峭,感觉我可以用一个简单的 Excel 表完成所有这些任务。你知道那种感觉,对吧?在线平台通常依赖概念练习,对生命科学家没有明显的应用,并提供过多的指导和许多指令。当您决定从头开始编写自己的代码时,您会发现自己正看着一张空白页,不知道如何开始。两件事让我克服了这些困难,更快地跳到了那个学习曲线的上部: 边做边学 和**熊猫,**一个强大的 Python 的数据科学库。

本质上是指一种更具实践性的方法。阅读代码不是编码。您需要迈出这一步,开始在您的机器上编写代码。我试图用 Python 再现我在 Excel 或 OriginLab 中可以做的事情,例如,处理数据、绘图、应用统计测试以及将数学模型与我的实验数据相匹配。我不得不花费大量的时间调试和查看他人的代码来理解和修复我的错误,但最终,这是对我来说最有成效的策略:弄清楚如何让一些有意义的东西工作,调用非常支持的 python 社区(google 是你的朋友!),调查错误消息以修复我的问题,并在此过程中学习。

有许多语言,但 Python 对我来说是理想的——开源,非常直观,并拥有针对常见科学问题的大量科学库。熊猫只是让 Python 更加出色! Pandas 可以说是 Python 中最重要的数据科学库,也是说服非程序员深入研究编码的一个很好的工具。熊猫依赖于一种叫做DataFrame的数据结构。这类似于一个 Excel 电子表格,包括各种内置函数,用很少的编程知识就可以操作和分析数据。

开始使用 Anaconda

*如果你认为自己是一个'*琼恩·雪诺'谈到代码(你一无所知!开头可能会引起愤怒。你需要与命令行交互,在黑色的屏幕上写下抽象的文字,只是为了下载软件和软件包,很快你就会感觉自己迷失在矩阵中。然而,Python 通过 Anaconda 提供了一种替代初始压力的方法(至少目前如此)。Anaconda 发行版像其他软件一样工作:从网页下载并安装。Anaconda 不仅包括 python 的最新版本,还包括许多用于数据科学的标准库,否则必须从命令行手动安装。这些包包括用于许多科学计算任务的numpyscipy,以及 Python 中最常用的可视化库matplotlib。事实上,熊猫是建立在numpy之上的,与scipymatplotlib配合得非常好。Anaconda 附带了其他开源平台,包括 R studio、和两个用于 python 的 ide(集成开发环境)(spyderjupyther )。ide 基本上是编写和编译代码的编辑器。有很多,这可能是另一个混乱的来源。然而,jupyter 通常是生命科学家的一个很好的起点。它们比许多其他 ide 更简单,并提供了一种笔记本式的风格,用户可以同时拥有代码、情节和笔记。

下面,我用一个 jupyter 笔记本熊猫做了一个简短而温和的介绍。如果您的机器上安装了 anaconda,那么您已经准备好跟随它了。本指南使用了一个公众熟知的乳腺癌症诊断数据集。我的目标是说明你可以用有限的编程技能做多少关于熊猫的事情,也许会激励你从这里开始学习更多。在介质上处理代码的灵活性非常有限,所以我分享一个 github 链接,其中包含一个 jupyter 笔记本,上面有我在这里展示的所有例子。我们可以开始了吗?

读取&操纵数据

每一个 python 脚本都以几个import命令开始,用户在这里设置他们想要使用的库/包,除了那些已经默认包含在 raw 语言中的库/包。你可以把它们想象成包含不同功能和参数的文件夹。按照惯例,我们import将它们打包,并用它们名字的较短版本来表达,以避免在文档中写太多的单词。例如,我们使用import pandas as pd,这样我们就不必每次想使用库时都写pandas,只需写pd。同样适用于npplt而不是它们的全名。

下面的脚本显示了如何使用pandas中的pd.read_csv函数加载数据集。该功能直接从您机器上的文件夹中读取.txt.csv文件,并以一种让您想起典型电子表格的格式显示数据。我们将函数的输出归属于一个变量(breast_cancer_data),以便在脚本中使用它。

如何用熊猫读取文件

乳腺癌诊断数据集(来源)

我们的数据集包含 569 个样本(患者)、分类数据(诊断结果)和数值数据(与肿瘤形状和大小相关的 31 个属性,以及每个患者的 id)。我们现在已经准备好按照我们的意愿开始探索和操作数据。下面的脚本展示了几个简单操作的例子,只需一行代码就可以实现。

熊猫的基本操作

注意,这里我们只是检查给定函数的输出,而不是永久地改变数据。为了做到这一点,我们需要为每个操作的输出添加一个新的变量。或者,我们也可以使用参数inplace = True,它告诉pandas我们想要直接在原始表上实现动作。为了总结第一部分,我们可以使用上面的一些函数创建数据的子集,用于下一部分,我们称之为breast_cancer_data_subset

创建新表:breast_cancer_data_subset

乳腺癌数据子集

基本操作

当您开始探索大型数据集时,pandas中的两个有用工具是pd.describe()函数和pd.corr()函数,前者返回所有数字列的汇总统计数据,后者返回数据框中所有列之间的相关性。下面你可以分别看到它们的样子。

乳腺癌数据子集描述()输出

乳腺癌数据子集 corr()输出

请注意,仅用两行简单的代码就可以从数据中检索出多少信息!这些函数只使用包含数字数据的列,因此没有显示诊断列。可以按照类似的模式应用其他简单的操作。这里还有几个例子。

总的来说,排序,计数,切片和基本的数学运算可以毫不费力地应用。所有函数通常都包含可选参数,这些参数可以让我们对它们的输出进行更多的控制。关于每个参数作用的详细信息可在pandas文档中找到。

可视化数据

我们上面所做的所有操作都是可能的,因为pandas是建立在科学计算的基础包numpy之上的。同样,pandas也整合了部分matplotlib库来创建快速的数据可视化。为此,我们使用plot()函数,并将变量(xy)和绘图类型(kind)设置为该函数的参数。

和熊猫一起策划

**

散点图:纹理与半径

就我个人而言,我宁愿直接使用matplotlib库来绘制数据,在那里我对颜色、轴、大小和形状有更多的控制。然而,为了讨论的缘故,我将坚持用pandas向你展示这些情节已经可以有多么丰富的信息和视觉吸引力。实际上,有另一个基于matplotlib的数据可视化库叫做seaborn,它与pandas.配合得非常好。这是本文主要目标的一个小弯路,但是seaborn是一个非常棒的相关性可视化工具,比单独使用matplotlib来创建盒状图要好,并且对初学者来说非常用户友好。这里有一个例子。

相关矩阵的 seaborn 热图

seaborn pairplot 函数。诊断结果用于将数据分成两组

从这些例子中可以看出,seaborn非常有助于初步了解多个变量之间的相关性。此外,它还提供了一种使用sns.boxplot功能直接从数据框绘制箱线图的简单方法。下面的代码片段展示了如何操作。

seaborn 箱线图诊断与面积

通过结合pandasseaborn可以做更多的事情,但是这只是一个展示,即使知道太少也可以做多少事情。

过滤和分组

最后,让我介绍两种方便的技术:使用简单条件参数的数据过滤和groupby函数,可以说是pandas提供的最好工具之一。条件遵循一个简单的模式,我们定义我们想要应用于一列或一行的条件(例如><==),我们以调用列的相同方式传递该条件。可以使用符号|()和& ( )组合多个条件。这里有一些例子。

输出:肿瘤面积和周长分别大于 1000 和 180 的患者

最后,groupby函数根据给定列中的分类或数字标签将数据分组。然后,数学运算可以分别应用于这些组中的每一组。在我们的示例中,诊断列中的两个标签(B 或 M)可用于此目的,使我们能够研究每个类别(良性和恶性肿瘤)中的数据有何不同。

breast _ cancer _ data _ subset . group by('诊断')。中位数()

breast _ cancer _ data _ subset . group by('诊断')。更正()

两组相关矩阵的 seaborn 热图

通过简单地应用groupby函数,我们可以快速比较数据中不同的基础人群,并调查特征之间的差异是否具有统计相关性。我发现这个功能非常有用,我可以围绕它再写一篇文章。也许在后续的帖子里。

包装

这只是你可以用pandas结合matplotlibseaborn做的事情的冰山一角。也许这篇文章可以激励你去拿一个你自己的数据集并开始实验。从这里,您可以很快推断出其他库,如scipy,它可以用来将数学模型与数据相匹配,并应用统计测试。

当然,这篇短文并没有为您提供 python 语言的所有构件。最终,你将不得不更深入地学习不同的数据类型(字符串、列表、数组和字典)以及类似循环的或列表理解的*。然而,通过用这种语言构建一些有意义的东西,而不仅仅是在线解决随机的任务,可能会给你一些额外的动力,让你继续前进,并在前进的道路上找到所有的东西。学习如何编程是一项真正的赋权技能,不仅可以提升你的职业前景,还可以平稳地导航这个技术时代。*

熊猫给新手:介绍第一部分

原文:https://towardsdatascience.com/pandas-for-newbies-an-introduction-part-i-8246f14efcca?source=collection_archive---------37-----------------------

当谈到熊猫和蟒蛇时,我们都从同一个地方开始。照片由 Pexels 的 Victoria Borodinova 拍摄

对于那些刚刚开始学习数据科学的人来说,Python 编程语言是学习数据科学的先决条件,所以如果你不熟悉 Python,请熟悉一下,然后回到这里开始学习 Pandas。

你可以从我刚刚开始的一系列文章开始学习 Python,这些文章叫做数据科学所需的最小 Python。

谈到数据科学,工具箱中最重要的工具之一是 pandas,这是 Wes McKinney 在对冲基金任职期间开发的 Python 数据分析库。

在这整个系列的文章中,我们将使用 Anaconda ,它是一个面向数据科学和机器学习的奇特的 Python 包管理器。如果您不熟悉我刚刚谈到的内容,请继续观看这个视频,它将向您介绍 Anaconda 和 Jupyter Notebook,这是数据科学工作的核心。

您可以通过以下方式激活 conda 环境(虚拟环境):

$ conda activate [name of environment]# my environment is named `datascience` so$ conda activate datascience

激活 conda 虚拟环境后,您应该会在终端上看到:

(datascience)$

假设您的系统上安装了 miniconda 或 anaconda,您可以很容易地安装 pandas:

$ conda install pandas

我们还将使用 Jupyter Notebook 来编写代码,请继续

$ conda install -c conda-forge notebook

启动 Jupyter 笔记本:

$ jupyter notebook

熊猫是把所有东西粘在一起的粘合剂

照片由尤哈什·伊姆雷从派克斯拍摄

随着我们在数据科学的更高层次上冒险进入机器学习领域,熊猫变得越来越重要,因为它允许数据在进入随机森林和神经网络等算法之前被“清洗”和“争论”。如果 ML 算法是 Doc,那么熊猫就是马蒂。

有导游的巴士旅游

我的最爱。文卡特·拉加文摄于 Pexels

我从小就喜欢去的地方之一是圣地亚哥动物园。我经常做的一件事就是一边喝着蓝月亮一边坐有导游的巴士旅游。

我们将做一些类似的事情,我将简单介绍一下你可以对熊猫做的一些事情。你独自面对蓝月亮。

这个中型系列的数据和灵感都来自 Ted Petrou 关于 Dunder Data 的优秀课程。

Pandas 主要处理表格数据:行和列。在这方面,它非常像一个 Excel 电子表格。

在 pandas 中,您将与两个主要对象交互,即系列数据框。数据帧是由行和列组成的二维数据。

如果你不知道下面的代码是做什么的,没关系,我们稍后会详细讲解。我们在这里使用的数据是关于芝加哥的骑自行车的人,Illnoise。

数据框架:表格数据

Series 是一维数据或相对于 DataFrame 的单列数据:

系列:单列数据

如上所示,pandas 的一个亮点是它允许将数据从任何源文件加载到 Jupyter 笔记本会话中,无论是 CSV(逗号分隔)、XLSX(Excel)、SQL 还是 JSON。

我们经常做的第一件事就是通过使用head方法来查看我们正在研究的数据集。默认情况下,head将显示前五行数据。我们可以传递一个整数来控制我们希望看到多少行:

df.head(7)

前七排

如果我们想看到最后五行:

df.tail()

读入数据

我们使用read_csv函数来加载 CSV 格式的数据。

我们将包含数据的文件路径作为字符串传递给 pandas 的read_csv方法。在我的例子中,我使用的是我的 GitHub Repo 的 url,它保存了我将要使用的所有数据。我强烈推荐阅读关于熊猫read_csv功能的文档,因为它是整个图书馆中最重要和最动态的功能之一。

过滤数据

我们可以用条件逻辑过滤熊猫数据帧的行。对于熟悉 SQL 的程序员来说,这就像使用WHERE子句。

要仅检索wind_speed大于 42.0 的行,我们可以这样做:

过滤器变量代表“过滤器”

我们可以像这样过滤多个条件:

这里我们过滤风速大于 42.0(我假设是每小时英里数)和骑车人的性别是女性的情况。正如我们看到的,它返回一个空数据集。

我们可以通过尝试相同的多个过滤器来验证我们没有犯某种导致空查询的错误,但是对于男性骑手。

我们也可以这样做:

查询:过滤的一种更简单的替代方法

Pandas 也有一个query方法,它的能力有点受限,但是允许更简单和更可读的代码。和以前一样,熟悉 SQL 的程序员应该会对这种方法感到很舒服。

待续

《熊猫给新手》是一个中等系列,所以请关注下一个即将发布的教程 熊猫给新手:介绍第二部分 ,它将很快发布。

熊猫给新手:介绍第二部分

原文:https://towardsdatascience.com/pandas-for-newbies-an-introduction-part-ii-9f69a045dd95?source=collection_archive---------44-----------------------

来自 Pexels 的 Victoria Borodinova 的照片

本文是上一篇文章的延续,上一篇文章开启了学习 Python 进行数据分析的旅程。你可以在这里查阅以前的文章:熊猫给新手:介绍第一部分。

对于那些刚刚开始学习数据科学的人来说,Python 编程语言是学习数据科学的先决条件,所以如果你不熟悉 Python,请熟悉一下,然后回到这里开始学习 Pandas。

你可以从我刚刚开始的一系列文章开始学习 Python,这些文章叫做数据科学所需的最小 Python。

作为一个提醒,我在这里做的是一个简短的旅行,只是一些你可以用熊猫做的事情。这是真正的深潜之前的深潜。

这个系列的数据和灵感都来自 Ted Petrou 关于 Dunder Data 的优秀课程。

先决条件

  1. 计算机编程语言
  2. 熊猫
  3. 朱皮特

一旦你把这三件事都准备好了,你就可以开始了。

聚合

我们上次停止了使用 pandas query方法作为通过布尔条件逻辑进行常规过滤的替代方法。虽然有它的局限性,但是query是一个可读性更好的方法。

今天我们继续讨论汇总,这是用一个数字汇总数据的行为。示例包括总和、平均值、中值、最小值和最大值。

让我们在不同数据集上尝试一下。

通过调用 mean 方法得到平均值。

students.mean()math score       66.089
reading score    69.169
writing score    68.054
dtype: float64

使用axis参数来计算各行中所有分数(数学、阅读和写作)的总和:

scores = students[['math score', 'reading score', 'writing score']]scores.sum(axis=1).head(3)0    218
1    247
2    278
dtype: int64

非聚集方法

对数据执行计算,不一定要聚合数据。即round方法:

scores.round(-1).head(3)math score  reading score  writing score0          70             70             701          70             90             902          90            100             90

在组内聚集

让我们获得单个列中唯一值的频率。

students['parental level of education'].value_counts()some college          226
associate's degree    222
high school           196
some high school      179
bachelor's degree     118
master's degree        59
Name: parental level of education, dtype: int64

使用groupby方法创建一个组,然后应用和聚合。这里我们得到了每个性别的平均数学分数:

students.groupby('gender').agg(mean_math_score=('math score', 'mean')
)mean_math_scoregenderfemale        63.633205male          68.728216

多重聚集

这里我们同时进行多个聚合。

students.groupby('gender').agg(mean_math_score=('math score', 'mean'),max_math_score=('math score', 'max'),count_math_score=('math score', 'count')
)

我们可以从多个列创建组。

students.groupby(['gender', 'test preparation course']).agg(mean_math_score=('math score', 'mean'),max_math_score=('math score', 'max'),count_math_score=('math score', 'count')
)

看起来,为两性考试做准备的学生比没有做准备的学生得分更高。

数据透视表

向信息消费者呈现信息的更好方法是使用pivot_table函数,该函数与groupby做同样的事情,但是使用一个分组列作为新列。

同样,同样的信息以更易读、更直观的格式呈现。

数据争论

让我们用一个新的数据集来检查缺失值的数据集

提供na_values参数会将数据集中的空值标记为 NaN(不是数字)。

您可能还会遇到这样的数据集,其中所有的列都应该是一列的一部分。

我们可以使用melt方法一个接一个地堆叠列。

合并数据集

学习熊猫库的这一部分时,了解一点 SQL 会派上用场。

在 pandas 中有多种连接数据的方法,但是您应该非常熟悉的一种方法是merge方法,它基于一个或多个键连接数据帧中的行。它基本上是 SQL 连接的一个实现。

假设我有来自电影租赁数据库的以下数据:

使用merge执行“内部”连接:

SQL (PostgreSQL)的等价形式如下:

SELECT * FROM customer
INNER JOIN payment 
ON payment.customer_id = customer.customer_id
ORDER BY customer.first_name ASC
LIMIT 5;

时间序列分析

熊猫这个名字实际上来源于面板数据分析,该分析将横截面数据与在医学研究和经济学中最广泛使用的时间序列相结合。

假设我有以下数据,我知道它是时间序列数据,但没有用DatetimeIndex指定它是时间序列:

p      a0  0.749  28.961  1.093  67.812  0.920  55.153  0.960  78.624  0.912  60.15

我可以简单地将索引设置为一个DatetimeIndex,用:

这导致:

p       a1986-12-31  0.749   28.961987-12-31  1.093   67.811988-12-31  0.920   55.151989-12-31  0.960   78.621990-12-31  0.912   60.151991-12-31  1.054   45.541992-12-31  1.079   33.621993-12-31  1.525   44.581994-12-31  1.310   41.94

这里我们有一个数据集,其中 p 是因变量,a 是自变量。在运行名为 AR(1)的计量经济模型之前,我们必须滞后因变量来处理自相关,我们可以使用:

p      a  p_lagged1986-12-31  0.749  28.96       NaN1987-12-31  1.093  67.81     0.7491988-12-31  0.920  55.15     1.0931989-12-31  0.960  78.62     0.9201990-12-31  0.912  60.15     0.960

形象化

matplotlibpandas的结合让我们可以在眨眼之间制作出基本的简单情节:

# Using the previous datasetbangla.plot();

pivot_scores.plot(kind='bar');

这就结束了我们对熊猫数据分析工具箱的简短巴士之旅。在我的下一系列文章中,我们将深入探讨更多内容。敬请关注!

熊猫小组:一个简单而详细的教程

原文:https://towardsdatascience.com/pandas-groupby-a-simple-but-detailed-tutorial-314b8f37005d?source=collection_archive---------15-----------------------

Groupby 是一个很好的生成分析的工具,但是为了充分利用它并正确使用它,这里有一些众所周知的技巧

由德克·冯·隆-瓦格纳在 Unsplash 上拍摄的照片

Pandas groupby 是一个相当强大的数据分析工具。但是对于初学者来说使用起来并不是很直观,因为 groupby 的输出并不是 Pandas Dataframe 对象,而是 Pandasdata frame group by对象。DataFrame 对象可以很容易地被可视化,但对于 Pandas DataFrameGroupBy 对象来说却不是这样。如果一个物体不能被可视化,那么它就更难被操纵。

我在网上找到的一些教程要么包含了太多对用户来说不必要的信息,要么没有足够的信息让用户知道它是如何工作的。我认为包含数据科学家日常工作中经常使用的关键工具的指南肯定会有所帮助,这就是为什么我写这篇文章来帮助读者更好地了解 pandas groupby。

重要注意事项
1。我假设读者在开始之前,已经知道了在 R、SQL、Excel(或其他工具)中 group by 计算是如何工作的。
2。所有代码都经过测试,它们适用于熊猫 1.0.3 。旧的熊猫版本可能会有错误。

每一节都将提供示例—可能有不同的方法来生成相同的结果,我会选择我经常使用的方法。

大纲如下:

  1. 使用创建分析。 groupby() 和**。agg()** :内置函数
  2. 使用创建分析。 groupby() 和**。agg()** :用户定义的函数和 lambda 函数
  3. 使用**。transform()** 将组统计数据连接到原始数据帧
  4. 分组处理时间序列

使用创建分析。 groupby() 和**。agg()** :内置函数

为了生成数据集中每个组的统计数据,我们需要根据一个或多个列将数据分类成组。

# group by a single column
df.groupby('column1')# group by multiple columns
df.groupby(['column1','column2'])

然后,我们决定想要创建什么样的统计数据。这可以用.agg()来完成。使用.agg()有几种不同的方式:

A.使用字典作为.agg()的输入。
B .使用单个聚合函数或聚合函数列表作为输入。
C .使用命名聚合(Pandas 0.25.0 中的新功能)作为输入。

我将用下面的例子来演示这些不同的解决方案是如何工作的。

import pandas as pd
import numpy as np 
df = pd.DataFrame(dict(Gender=['M', 'F', 'M', 'F','F', 'M', 'M', np.nan],State=['NY','IL', 'NY', 'CA','IL', 'CA', 'CA', 'IL'],col_1=[10,20,30,np.nan,40,50,60,70],col_2=[1,6,2,4,6,9,np.nan,3]))

A .字典 什么时候用?— 当我们需要在不同的列上运行不同的聚合,并且我们不关心聚合列的名称是什么样子时。

对于字典中的每个键-值对,键是我们想要运行聚合的变量,值是聚合函数。

tbl = df.groupby(['Gender','State'])\.agg({'col_1': ['mean', 'std'],'col_2': [sum, 'size' ,'count']})

如果对于每一列,只使用一个聚合函数,那么我们就不必将聚合函数放在一个列表中。在这种情况下,tbl将是单索引的,而不是多索引的。

tbl = df.groupby(['Gender','State'])\.agg({'col_1': 'mean','col_2': sum})

B .单个聚合函数或者列表聚合函数 什么时候使用?— 当我们需要对所有列运行相同的聚合,并且我们不关心聚合列的名称是什么样子时。

如果我们想对每一列应用相同的集合函数,我们只需要在.agg()中包含一个函数或一列函数。

tbl = df.groupby(['Gender','State'])\.agg([min, max])    # a list of aggregation functions

如果我们只想查看选定列的结果,我们可以在代码中应用过滤器:

# filter by a single column
tbl = df.groupby(['Gender','State'])\['col_1'].agg([min, max]) tbl = df.groupby(['Gender','State'])\[['col_1']].agg([min, max])# filter by a multiple columns
tbl = df.groupby(['Gender','State'])\['col_1', 'col_2'].agg([min, max])tbl = df.groupby(['Gender','State'])\[['col_1', 'col_2']].agg([min, max])

**注。**如果我们按多列过滤,那么无论使用哪种方法,tbl.columns都是多索引的。如果我们按单列过滤,那么[['col_1']]使tbl.columns成为多索引,而['col_1']使tbl.columns成为单索引。

C .命名聚合(熊猫≥ 0.25) 什么时候用?— 当我们需要在不同的列上运行不同的聚合时,我们希望在运行.agg()后能够完全控制列名

在每个元组中,第一个元素是列名,第二个元素是聚合函数。

tbl = df.groupby(['Gender','State'])\.agg(col_1_mean=('col_1','mean'),col_1_max=('col_1',max),col_2_sum=('col_2',sum))

关于 .agg()的几点说明。

  1. 数据按列 A 和列 B 分组,但列 A 中有缺失值。在任一列中有缺失值的行将从使用.agg()生成的统计数据中排除。
  2. 对于使用 sum、max、min、【中值】、【均值】、【计数】(非空元素的计数)、、【标准】、、【唯一】、(不同元素的计数)创建的组统计,数据中缺失的值将从计算中排除。但是‘size’(所有元素的计数)仍然包括缺失值。
  3. 可以做 tbl.columns =["_".join(i) for i in tbl.columns.ravel()]将多索引列转换成单索引列。
  4. 可以使用tbl = tbl.reset_index()将索引转换为表
    的列。
  5. 在使用.agg()创建的表格中,组可能没有按照首选顺序排列。一个人可以
df['Gender'] = pd.Categorical(df['Gender'], ['F', 'M'])
df['State']  = pd.Categorical(df['State'],  ['NY', 'CA', 'IL'])

在运行.agg()之前,将列转换为用户指定级别的分类系列。(注。pd.Categorical可能不适用于较老的熊猫版本)

使用创建分析。 groupby() 和**。agg()** :用户定义的函数和 lambda 函数

让我们看另一个例子,看看我们如何在.agg()中使用用户定义的函数或 lambda 函数来计算统计数据。

df = pd.DataFrame(dict(StoreID=[1,1,1,1,2,2,2,2,2,2],ProductID=['A01', 'A02', 'B01','C01',  'B01', 'B02', 'B03', 'C01', 'C02', 'C03'],price=[10,20,50,100,50,60,70,100,150,200]))

我们希望计算每个商店的以下统计数据:
A .以“A”开头的产品数量
B .所有产品的列表
C .最高产品价格和最低产品价格的差异
D .产品价格的第一个分位数(第 25 个百分位数)

首先,我们定义一个函数来计算一个序列中以“A”开头的元素的数量。

def cnt_A(x):ctr = 0for item in x:if item[0] == 'A':ctr += 1return ctr# If you prefer a Pythonic approach:  
def cnt_A(x):return (x.str[0] == 'A').sum()

然后,我们可以使用命名聚合+用户定义函数+ lambda 函数来优雅地完成所有计算。

df.groupby(['StoreID'])\.agg(number_of_product_A =('ProductID', cnt_A),product_list=('ProductID', lambda x: ', '.join(x)),price_Q1    =('price', lambda x: np.percentile(x, 25)),price_gap   =('price', lambda x: x.max()-x.min()))

当函数不复杂时,使用 lambda 函数会使您的生活更轻松。lambda x: x.max()-x.min()

def gap(x):return x.max()-x.min()

生成相同的输出。

。如果在有重复的时候你需要一个唯一的列表,你可以用lambda x: ', '.join(x.unique())代替lambda x: ', '.join(x)

使用**。transform()** 将组统计信息附加到原始数据中

让我们使用上一节中的数据来看看如何使用.transform()将组统计信息添加到原始数据中。

df = pd.DataFrame(dict(StoreID=[1,1,1,1,2,2,2,2,2,2],ProductID=['A01', 'A02', 'B01','C01',  'B01', 'B02', 'B03', 'C01', 'C02', 'C03'],price=[10,20,50,100,50,60,70,100,150,200]))df['cnt A in each store'] = df.groupby('StoreID')['ProductID']\.transform(cnt_A)

使用.transform(),我们可以轻松地将统计数据添加到原始数据集。

**注 1。**与.agg()不同,.transform()不以字典为输入。
**注二。**为了正确地追加数据,我们需要确保.groupby()中使用的列中没有缺失值。(根据 Pandas 用户指南,.transform()返回与被分组的对象索引相同(大小相同)的对象。)

示例—百分比计数:

df = pd.DataFrame(dict(bank_ID=[1,1,1,1,2,2,2,2,2],acct_type=['checking','checking', 'checking','credit','checking','credit', 'credit','credit', 'checking']))

问题:如何计算各银行账户类型的百分比?首先,我们计算每个 bank_ID + acct_type 组合的组总数:

tbl = df.groupby(['bank_ID', 'acct_type'])\.agg(group_total=('acct_type','count'))\.reset_index()

然后计算每个银行的总数,并使用.transform()添加信息。

tbl['total count in each bank'] = tbl.groupby('bank_ID')\['group_total']\.transform(sum)
tbl['% in each bank'] = (tbl['group_total'] * 100.0 / tbl['total count in each bank'])

另一个没有.transform()的解决方案:只按 bank_ID 分组,用pd.merge()把结果联接回tbl

分组处理时间序列

import datetime
df = pd.DataFrame(dict(acct_ID=['A102','A102','A102','A102','A102','A102','D276','D276','D276','D276','D276'],transaction_time=[datetime.datetime(2016, 3, 1, 11, 0),datetime.datetime(2016, 4, 12, 9, 0),datetime.datetime(2016, 4, 14, 12, 0),datetime.datetime(2016, 4, 14, 17, 0),datetime.datetime(2016, 4, 20, 13, 0),datetime.datetime(2016, 6, 11, 20, 0),datetime.datetime(2018, 7, 11, 10, 0),datetime.datetime(2018, 7, 12, 10, 0),datetime.datetime(2018, 9, 24, 9, 0),datetime.datetime(2018, 9, 24, 12, 0),datetime.datetime(2018, 12, 20, 15, 0)],transaction_amount=[20, 100, 120, 100, 40, 60, 80, 200, 200, 80, 50]))

对于上面的交易数据,我们希望将以下各列添加到每个交易记录中:

  1. 交易行号(按交易时间排序)
  2. 前一笔交易的交易金额
  3. 前一笔交易与当前交易的交易金额差额
  4. 前一个交易与当前交易之间的时间间隔(以天为单位,向下舍入)
  5. 截至当前交易的所有交易的累计总额
  6. 截至当前交易的所有交易的累计最大值
  7. 截至上一笔交易的所有交易的累计总额
  8. 截至前一笔交易的所有交易的累计最大值

注。在进行以下计算之前,请确保先对数据进行排序。该表已经排序,但如果没有排序,您可以执行df.sort_values(by=['acct_ID','transaction_time'], inplace=True)

对于 1。,我们能做什么

df['rowID'] = df.groupby('acct_ID')['transaction_time']\.rank(method='first', ascending=True)\.astype(int)

两个人的。-6.,可以通过以下代码轻松完成:

df['prev_trans']  =df.groupby('acct_ID')['transaction_amount']\.shift(1)
df['trans_diff']  =df.groupby('acct_ID')['transaction_amount']\.diff(1)
df['time_diff']   =df.groupby('acct_ID')['transaction_time']\.diff(1).dt.days
df['trans_cumsum']=df.groupby('acct_ID')['transaction_amount']\.cumsum()
df['trans_cummax']=df.groupby('acct_ID')['transaction_amount']\.cummax()

为了得到 7。和 8。,我们简单的把.shift(1)加到 5。和 6。我们计算出:

df['trans_cumsum_prev']  = df.groupby('acct_ID')['trans_cumsum']\.shift(1)
df['trans_cummax_prev']  = df.groupby('acct_ID')['trans_cummax']\.shift(1) 

所有这些计算的关键思想是,像
.rank().shift().diff().cummax().cumsum()这样的窗口函数不仅适用于熊猫数据帧,也适用于熊猫分组对象。

让我们看看运行上面的计算后会得到什么。结果被分成两个表。

读者可以使用不同的参数来使用这些窗口函数,看看会发生什么(比如说,试试.diff(2).shift(-1)?).

读者提问 :
1。我们如何计算不同窗口大小的交易金额的移动平均值?(提示:组合.shift(1).shift(2)、…)
2。我们如何按照降序来计算事务行号?(提示:使用.rank()中的ascending参数——参见此链接。)

*

教程到此结束,感谢阅读。欢迎提出建议——欢迎在评论中发表新想法/更好的解决方案,这样其他人也可以看到它们。

熊猫分组——解释

原文:https://towardsdatascience.com/pandas-groupby-explained-453692519d0?source=collection_archive---------13-----------------------

如何高效利用熊猫的分组功能

Pandas 是一个非常强大的 Python 数据分析库,可以加速项目的预处理步骤。在这篇文章中,我将用许多例子来介绍熊猫的功能,帮助你全面理解这个功能。

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

Groupby 是一个多功能且易于使用的函数,有助于获得数据的概览。这使得探索数据集和揭示变量之间的潜在关系变得更加容易。

Groupby 最好通过例子来解释。我将使用 Kaggle 上可用的客户流失数据集。我只取了其中足以展示 groupby 函数每个细节的一部分。

一如既往,我们从进口熊猫开始:

import pandas as pd
import numpy as np

让我们快速看一下数据集:

df.shape
(7043, 9)df.head()

该数据集包括关于客户以及客户是否离职(即离开公司)的 8 个特征。

在对数据集应用 groupby 函数之前,让我们先看一个可视化的例子。可视化总是解释概念的好方法。假设我们有两个特征。一个是颜色,它是分类特征,另一个是数值特征,即值。我们希望颜色对值分组,并计算不同颜色值的平均值**(或任何其他集合)。然后最后基于平均值对颜色进行分类。下图显示了此过程的步骤。**

让我们回到我们的数据集。为了查看性别是否在搅动中起作用,我们可以将性别搅动列按性别分组。然后我们可以应用均值函数。

男性和女性的流失率非常接近。

如果我们不选择列并直接将 groupby 应用于数据框架,所有数值列都将根据聚合函数进行计算:

似乎所有的数字特征对男性和女性来说都大致相同。

我们还可以通过添加 sort_values 函数对结果进行排序:

默认情况下,它按升序排序。我们可以通过设置上升参数为假来改变它。

拥有光纤互联网服务的客户比其他客户更容易流失。

我们可以通过在方括号中传递列名来根据多个列进行分组:

“合同”栏有 3 个类别,“老年人”栏有 2 个类别,所以我们总共有 6 个组。对于每个组,计算平均“流失”率。

多个聚合函数

在某些情况下,应用 groupby 函数后,您可能希望查看不同组的计数和平均值。如果类分布不均衡,只查均值可能会造成错误的假设。您可以对 groupby 的结果应用多个聚合函数。它们不仅限于计数和均值,你可以将函数的名称作为参数传递给 agg() 函数。

as_index 参数

groupby 函数中的变量作为结果数据帧的索引返回。我们可以通过设置 as_index 参数为 false 来改变它。

让我们看看每月费用是否取决于合同类型。我们需要从数据集中提取“contract”和“MonthlyCharges”列,按“contract”分组,并对结果应用均值函数。

正如预期的那样,长期合同的平均月费用较低。

我们可以根据任务应用其他聚集函数。例如,我们可能希望看到不同 internet 服务类型的合同类型分布。由于两者都是分类变量,我们可以应用计数函数:

因为我们应用了 count 函数,所以返回的 dataframe 包括所有其他列,因为它可以计算值,而不管 dataframe 是什么。所有列上的值的数量都是相同的,所以我们可以只选择一列来查看值。熊猫的一个好处是通常有不止一种方法来完成一项任务。

这三行返回以下输出:

您也可以执行如下相同的任务,但返回的对象将是 dataframe:

请注意,一些聚合函数需要数值。例如,如果我们只有分类变量并试图应用均值函数,我们将得到一个错误:

我们可以多样化的例子,但基本的逻辑是相同的。Groupby 函数可用作探索性数据分析过程的第一步,因为它让我们了解数据集中变量之间的关系。

感谢阅读。如果您有任何反馈,请告诉我。

Pandas Groupby vs SQL Group By

原文:https://towardsdatascience.com/pandas-groupby-vs-sql-group-by-39ccd7d2b779?source=collection_archive---------20-----------------------

举例说明

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

Pandas 是 Python 的一个数据分析和操作库。SQL 是大多数关系数据库管理系统(RDBMS)用来管理数据库的编程语言。它们的共同点是 Pandas 和 SQL 都操作表格数据(即表格由行和列组成)。

虽然有不同的语法,但类似的操作或查询可以使用 Pandas 或 SQL 来完成。典型数据分析过程中最常见的操作之一是根据数字特征比较类别。两者在执行此类任务时效率都很高。

在本帖中,我们将做很多例子来掌握这些操作是如何用熊猫的 groupby 函数和 SQL 的 GROUP BY 语句完成的。

下图说明了“groupby”操作背后的逻辑。

Groupby 操作(图片由作者提供)

我们将使用 Kaggle 上提供的客户流失数据集。对于熊猫,数据集存储在“变动”数据帧中。对于 SQL,数据在“变动”表中。

这是数据集的快照。

(图片由作者提供)

有一些功能可以提供关于客户及其银行账户的信息。“已离开”栏显示客户是否离开银行。

我将定义一些有助于我们探索数据集的度量,并使用 Pandas 和 SQL 来计算它们。

我们开始吧。

基于国家/地区的流失率

这将有助于我们了解不同国家的流失率是否存在差异。将 exited 列按 geography 列分组并取平均值将得到结果。

熊猫

churn[['Geography','Exited']].groupby('Geography').mean()

(图片由作者提供)

SQL

SELECT Geography, AVG(Exited)
FROM CHURN
GROUP BY Geography;

(图片由作者提供)

主要的区别在于我们应用聚合函数的地方。SQL 允许在选择列时直接应用函数,而在 Pandas 的 groupby 函数之后应用。

基于国家和性别的流失率

SQL 和 Pandas 都允许基于多个列进行分组,这可以提供更多的洞察力。例如,我们可能想要检查性别如何影响不同国家的客户流失。

我们将首先按性别对平均流失率进行分组,然后按国家分组。

熊猫

churn[['Gender','Geography','Exited']]\
.groupby(['Gender','Geography']).mean()

(图片由作者提供)

SQL

SELECT Gender, Geography, AVG(Exited)
FROM CHURN
GROUP BY Gender, Geography
ORDER BY Gender, Geography;

(图片由作者提供)

我添加了 ORDER BY 子句来匹配 Pandas 返回的顺序,并使它看起来更有结构。

对于 Pandas 和 SQL,分组中列的顺序对结果帧的结构很重要。这些值不会改变。

每个国家的平均余额和客户总数

Pandas 和 SQL 都提供了对不同的列应用不同的聚合函数的方法。例如,我们可能想要检查每个国家的平均余额和客户总数。

这是怎么做的。

熊猫

churn[['Geography','Balance','Exited']].groupby(['Geography'])\
.agg({'Balance':'mean', 'Exited':'sum'})

(图片由作者提供)

我们向 agg (aggregate)函数传递一个字典,指定哪个函数应用于哪个列。

SQL

SELECT Geography, AVG(Balance), SUM(Exited)
FROM CHURN
GROUP BY Geography;

(图片由作者提供)

使用 SQL 很简单,因为它允许我们在选择列时指定函数。

基于产品数量的平均和总流失率

我们可以在同一个数字列上应用多个聚合函数。如果类别之间不平衡,建议同时检查平均值和计数。在这种情况下,只检查平均值可能会产生误导。

让我们来看看产品数量和客户流失之间的关系。我们将计算平均流失率和流失客户总数。

熊猫

churn[['NumOfProducts','Exited']]\
.groupby('NumOfProducts').agg(['mean','count'])

(图片由作者提供)

因为只有一个数值列,所以我们不必向 agg 函数传递字典。我们将只使用函数列表。

SQL

SELECT NumOfProducts, AVG(Exited), COUNT(Exited)
FROM CHURN
GROUP BY NumOfProducts;

(图片由作者提供)

仅仅检查平均值会产生误导,因为拥有 2 件以上产品的客户数量远远少于拥有 1 件或 2 件产品的客户数量。

结果排序怎么样?

分组的目标是根据计算出的数值列找到具有高值或低值的类别。因此,排序是分组操作的一个重要部分。

SQL 和熊猫在排序上都很灵活。我们可以根据任何计算值和任何顺序进行排序。

考虑前面的查询,我们根据产品数量检查客户流失。

让我们对结果进行排序。

熊猫

可以使用 sort_values 函数。我们通常只传递其值将用于排序的列的名称。但是,如果使用多个聚合函数,我们需要传递一个指示列索引的元组。

以下代码将根据平均流失率(Exited,mean)对结果进行排序。

churn[['NumOfProducts','Exited']]\
.groupby('NumOfProducts').agg(['mean','count'])\
.sort_values(by=('Exited','mean'))

(图片由作者提供)

SQL

我们只需要在末尾添加一个 ORDER BY 子句。

SELECT NumOfProducts, AVG(Exited), COUNT(Exited)
FROM CHURN
GROUP BY NumOfProducts
ORDER BY AVG(Exited);

(图片由作者提供)

默认情况下,Pandas 和 SQL 都按升序对值进行排序。为了按降序排序,只需修改代码如下:

  • 熊猫:sort_values(by=(‘Exited’,’mean’), ascending=False)
  • SQL: ORDER BY AVG(Exited) DESC;

结论

正如我们在示例中看到的,Pandas 和 SQL 的分组背后的逻辑非常相似。一旦你熟悉了其中的一种,学习另一种就相当容易了。这只是一个语法问题。

如果你正在从事或者打算从事数据科学领域的工作,我强烈推荐你学习熊猫和 SQL。

感谢您的阅读。如果您有任何反馈,请告诉我。

熊猫有阅读 Excel 文件的超能力

原文:https://towardsdatascience.com/pandas-has-superpowers-in-reading-excel-files-44344bfdaac?source=collection_archive---------14-----------------------

Pandas 有不同的阅读器将数据读入数据框。其中一个是 Excel 阅读器。你知道即使你有一些复杂的财务管理报告,阅读器的功能有多强大吗?

照片由卢卡斯·布拉塞克在 Unsplash 上拍摄

大多数公司都有财务部门,他们制作带有关键数字和表格的 Excel 文件,并配有复杂的辅助计算和图表。似乎他们喜欢复杂的文件,里面有一堆表格和一个封面,上面显示了后面表格中数字的汇总。这些文件相对来说比较容易被人类理解。但如果你想作为一名数据分析师进入数字领域,你会面临一些障碍,因为乍一看没有逻辑结构。将工作表作为数据框读取会导致表格混乱。这些表通常在一页上有许多带有不同标题和布局的表格。你知道熊猫有一些打开和处理这种 Excel 文件的超能力吗?

Pandas Excel-Reader 功能强大,您不必使用复杂的 Python 脚本来整理整个数据框架。让我们用两个(半设计的)案例来看看一些特性。

在我的 GitHub 库中,我添加了示例文件和一个 Jupyter 笔记本以及一些注释。

熊猫 Excel-读者准备

在我们开始使用 pandas read_excel功能之前,我们必须安装 python 包xlrd。只需使用您最喜欢的软件包管理器并安装它。

conda install xlrd# orpip install xlrd

熊猫准备打开和阅读 Excel 文件。我已经准备了两个文件来解释一些很棒的特性。

一个简单的例子

让我们从第一个文件开始,一个有一张纸的简单文件。该表包含两个表格,一些解释,一个图表和辅助计算。

财务报表使用的表格示例

如果你用pd.read_excel('Filename.xlsx')读文件,你会得到一些杂乱无章的数据框。

试图读取文件时创建的数据帧

工作起来很费时间。但是不要害怕,熊猫会帮助你的!仔细看看这个表,我们会发现我们必须限制要读取的表的边界。熊猫 Excel 阅读器有一些很好的功能来传递列,哪一行是标题,应该读多少行。

让我们在这个简单的例子中深入研究这些参数。

第一个表位于 A 到 m 列之间,标题在第 2 行,我们需要读取 7 行。注意:不要计算标题行,这是隐含的。现在看看需要的参数。

为了定义标题,我们使用header。Header 要求工作表的行从 0 开始!Excel 从一开始计数!在我们的工作表中,我们需要第 2 行,这意味着我们将 1 作为标题参数传递。

我们对 A-M 列感兴趣。Pandas Excel reader 支持选择列的 Excel 语法。在这种情况下,我们有"A:M",我们将它作为一个字符串传递给usecols参数。我们需要的最后一个参数是熊猫应该读取的行数。相应的参数称为nrows,,我们传递 7,因为我们需要从第二行开始的七行!

让我们读一读有熊猫的表格:

df = pd.read_excel("demosheet1.xlsx", header=1, usecols="A:M", nrows=7)

我们的数据框现在包含了我们想要的表的清晰表示

去杂乱的数据帧,随时可用!

很好,不是吗?现在让我们读这张纸的第二张表。

df_employees = pd.read_excel("200910_Produktivitätsreport August 2020.xlsx", header=12, usecols="A:G", nrows=10)

工作表中第二个表格的数据框

标题位于第 13 行(记住,pandas 从 0 开始,所以我们传递 12),我们读取列 A-G,并且我们正在读取接下来的 10 行。第二桌就这样。

这是一个只有一张纸的简单文件。正如开头所说,大多数文件都更复杂。它们可能包含几页纸和一个封面。让我们来看看熊猫 Excel reader 如何处理这种工作表。

分而治之—更复杂的工作表

想象一下下面的例子。我们有一份带有封面的管理报告。在文件中,我们还有另外三张包含更多信息/数字的表格。它们都有相似的结构,除了有有趣数字的表格外,它们还包含描述和进一步的(对我们来说没用的)计算。我们对封面不感兴趣,因为我们希望使用以下表格中的数据。

如果 Pandas 读取这种类型的文件,它将只解释文件中找到的第一个工作表。在我们的例子中:封面。

现在让我们弄清楚如何用熊猫 Excel 阅读器阅读其他工作表。

阅读器支持一个名为sheet_name的参数,用于传递我们想要读取的工作表的编号或名称。让我们假设一个名为Sheet 1的工作表位于封面后的第二个位置,我们想要读取这个工作表。我们有两种选择来阅读表单:

  1. 通过位置从 0 开始计数,其中 0 是第一个,1 是第二个,依此类推。
  2. 将工作表的名称作为字符串传递。在这种情况下"Sheet 1"
# Pass the position
df = pd.read_excel("complex_one.xlsx", sheet_name=1)# Pass the name as a string
df = pd.read_excel("complex_one.xlsx", sheet_name='Sheet 1')

因为我们只对从第十行开始的数据感兴趣,所以我们只需传递上面示例中描述的参数来访问数据。

df = pd.read_excel("complex_one.xlsx", sheet_name='Sheet 1', header=9, usecols="A,B,D:H", nrows=19, )

您可以看到,我一直在使用一个更复杂的字符串来选择列。我使用 A,B 列和 D 到 h 列,我跳过了 C,因为它没什么意思。我的标题在第十行(记住熊猫是从 0 开始计数的),我总共要读取 19 行。19,因为该工作表的作者决定有 19 个可能的数据行。即使使用较少。

包含大量 nan 的数据帧

要去掉带有 NaN 的行,只需使用

df_sheet1 = df_complex.dropna()

没有那些 nan 的数据帧。

那很容易。但是在我们的 Excel 文件中还有两张工作表。该阅读器支持读取多张纸。sheet_name也可以处理工作表名称或编号的列表。你可以把名字和数字混在一起。

如果使用工作表列表,pandas 会返回一个包含数据框的字典。由于我们示例中的所有工作表都具有相同的结构,我们可以使用

df = pd.read_excel("complex_one.xlsx", sheet_name=['Sheet 1', 2, 3], header=9, usecols="A,B,D:H", nrows=19)

我们得到了三个结构相同的数据帧。现在,您可以进一步处理原始数据:

df_sheet1 = df_complex['Sheet 1'].dropna()
df_sheet2 = df_complex[2].dropna()
df_sheet3 = df_complex[3].dropna()

Pandas Excel reader 中最后一个有用的参数是设置列的数据类型。名为#的专栏被熊猫解释为 float 。但是它应该是一个对象,因为它包含一个雇员号。Excel reader 有一个名为dtype的参数,它需要一个带有。

Name_of_col: dtype

例如:

types = {'#': object
}df = pd.read_excel("complex_one.xlsx", sheet_name=['Sheet 1', 2, 3], header=9, usecols="A,B,D:H", nrows=19,dtypes=types)

现在#被解释为一个对象。不错!

下一步是什么,为什么?

熊猫 Excel 阅读器有更多的功能。阅读文档以获得更多灵感,在 pandas 中使用 Excel 表格可以做什么。

现在你可以从复杂的表格中读取原始数据,这些表格是为人类阅读而创建的。我们可以在阅读数据框的时候整理它们。下一步是用这些数据做出令人惊叹的东西。基于 Excel 创建由管理报告触发的仪表板、可视化和模型。或将数据添加到数据库等。由于 Excel 仍然是公司中几乎所有与数字打交道的人的首选工具,所以知道如何阅读和使用它们进行数据分析是很方便的。我希望你能学到一些新的东西,我很高兴看到笔记和评论。

1半设计,因为这些文件是基于我正在处理的真实世界场景。

熊猫加入 vs .合并

原文:https://towardsdatascience.com/pandas-join-vs-merge-c365fd4fbf49?source=collection_archive---------2-----------------------

罗马卡夫在 Unsplash 上拍摄的照片

它们有什么作用,我们应该在什么时候使用它们?

我写了很多关于统计和算法的文章,但是为建模准备数据也是数据科学的一个重要部分。事实上,很有可能你会花更多的时间盯着你的数据,检查它,修补它的漏洞,而不是训练和调整你的模型。

因此,我们在收集、清理和对数据执行快速“健全性检查”分析方面做得越好,我们就能在建模上花费越多的时间(大多数人认为这更有趣)。为此,让我们看看如何快速组合来自不同数据框架的数据,并为分析做好准备。

数据

让我们假设我们是一家生产和销售回形针的公司的分析师。我们需要运行一些关于我们公司销售部门的报告,以了解他们的工作情况,并从以下字典中获得数据:

import numpy as np
import pandas as pd# Dataframe of number of sales made by an employee
sales = {'Tony': 103,'Sally': 202,'Randy': 380,'Ellen': 101,'Fred': 82}# Dataframe of all employees and the region they work in
region = {'Tony': 'West','Sally': 'South','Carl': 'West','Archie': 'North','Randy': 'East','Ellen': 'South','Fred': np.nan,'Mo': 'East','HanWei': np.nan,}

我们可以从字典中创建两个独立的数据帧,如下所示:

# Make dataframes
sales_df = pd.DataFrame.from_dict(sales, orient='index', columns=['sales'])
region_df = pd.DataFrame.from_dict(region, orient='index', columns=['region'])

数据框架 sales_df 现在看起来像这样:

sales
Tony     103
Sally    202
Randy    380
Ellen    101
Fred      82

region_df 如下所示:

 region
Tony     West
Sally   South
Carl     West
Archie  North
Randy    East
Ellen   South
Fred      NaN
Mo       East
HanWei    NaN

我应该合并,加入,还是连接?

现在,让我们将所有数据合并到一个数据帧中。但是我们怎么做呢?

熊猫数据框架有很多类似 SQL 的功能。事实上,与 SQL 表相比,我更喜欢它们(全世界的数据分析师都对我虎视眈眈)。但是当我第一次开始用 Pandas 做许多类似 SQL 的东西时,我发现自己总是不确定是使用 join 还是 merge ,并且我经常互换使用它们(选择首先想到的)。那么我们应该在什么时候使用这些方法,它们之间到底有什么不同呢?好了,是时候不再困惑了!

加入

(如果你不熟悉什么是连接表,我写了这篇关于它的文章,我强烈建议你先读一读)

先从加入开始吧,因为这是最简单的一个。数据帧有一个叫做索引的东西。这是您的表的关键,如果我们知道索引,那么我们可以使用轻松地获取保存数据的行。loc 。如果你打印你的数据帧,你可以通过查看最左边的一栏来看索引是什么,或者我们可以更直接地使用**。索引**:

In:  sales_df.indexOut: Index(['Tony', 'Sally', 'Randy', 'Ellen', 'Fred'], dtype='object')

所以 sales_df 的指标就是我们销售人员的名字。顺便说一下,与 SQL 表的主键不同,数据帧的索引不必是唯一的。但是一个唯一的索引使我们的生活更容易,搜索数据帧的时间更短,所以它绝对是一个好东西。给定一个索引,我们可以像这样找到行数据:

In:  sales_df.loc['Tony']Out: sales    103Name: Tony, dtype: int64

好了,回到加入join 方法获取两个数据帧,在它们的索引上将它们连接起来(从技术上来说,您可以为左边的数据帧选择要连接的列)。让我们看看当我们通过 join 方法将两个数据帧组合在一起时会发生什么:

In:  joined_df = region_df.join(sales_df, how='left')print(joined_df)Out:        region  sales
Tony     West  103.0
Sally   South  202.0
Carl     West    NaN
Archie  North    NaN
Randy    East  380.0
Ellen   South  101.0
Fred      NaN   82.0
Mo       East    NaN
HanWei    NaN    NaN

结果看起来像一个 SQL 连接的输出,它或多或少是这样的。 join 方法使用索引或它所调用的数据帧中的指定列,也就是左边的数据帧,作为连接键。因此,我们为左侧数据帧匹配的列不一定是它的索引。**但是对于正确的数据帧,连接键必须是它的索引。**我个人觉得更容易把 join 方法理解为基于索引的连接,如果我不想在索引上连接,就使用 merge (即将出现)。

在组合数据框架中有一些 nan。那是因为不是所有的员工都有销售。没有销售的那些在 sales_df 中不存在,但是我们仍然显示它们,因为我们执行了一个左连接(通过指定“how=left”),它从左数据帧 region_df 返回所有的行,不管是否有匹配。如果我们不想在我们的连接结果中显示任何 nan,我们将改为执行内部连接(通过指定“how=inner”)。

合并

基本上,合并加入差不多。这两种方法都用于将两个数据帧组合在一起,但 merge 更通用,代价是需要更详细的输入。让我们看看如何使用合并创建与使用连接相同的组合数据帧:

In:  joined_df_merge = region_df.merge(sales_df, how='left', left_index=True,right_index=True)print(joined_df_merge)Out: region  sales
Tony     West  103.0
Sally   South  202.0
Carl     West    NaN
Archie  North    NaN
Randy    East  380.0
Ellen   South  101.0
Fred      NaN   82.0
Mo       East    NaN
HanWei    NaN    NaN

这与我们使用 join 时没有什么不同。但是 merge 允许我们为左右两个数据帧指定要连接的列。这里通过设置“左索引”和“右索引”等于真,我们让合并知道我们想要在索引上连接。我们得到了与之前使用 join 时相同的组合数据帧。

Merge 在我们不想在索引上连接的时候很有用。例如,假设我们想知道每个员工为他们的区域贡献了多少百分比。我们可以使用 groupby 来汇总每个地区的所有销售额。在下面的代码中, reset_index 用于将 region 从 data frame(grouped _ df)的索引转换为普通的列——是的,我们可以将它保留为索引并在其上连接,但是我想演示如何在列上使用 merge

In:  grouped_df = joined_df_merge.groupby(by='region').sum()grouped_df.reset_index(inplace=True)print(grouped_df)Out: region  sales
0   East  380.0
1  North    0.0
2  South  303.0
3   West  103.0

现在让使用 region 列合并 joined_df_merge 和 grouped_df。我们必须指定一个后缀,因为我们的两个数据框架(我们正在合并)都包含一个名为 sales 的列。后缀输入将指定的字符串附加到两个数据帧中具有相同名称的列的标签上。在我们的例子中,因为第二个 dataframe 的 sales 列实际上是整个地区的销售额,所以我们可以在它的标签后面加上“_region”来说明这一点。

In:employee_contrib = joined_df_merge.merge(grouped_df, how='left', left_on='region', right_on='region',suffixes=('','_region'))
print(employee_contrib) Out: region  sales  sales_region
0   West  103.0         103.0
1  South  202.0         303.0
2   West    NaN         103.0
3  North    NaN           0.0
4   East  380.0         380.0
5  South  101.0         303.0
6    NaN   82.0           NaN
7   East    NaN         380.0
8    NaN    NaN           NaN

哦不,我们的索引不见了!但是我们可以用 set_index 把它取回来(否则我们就不知道每行对应的是哪个员工):

In:employee_contrib = employee_contrib.set_index(joined_df_merge.index)
print(employee_contrib) Out: region  sales  sales_region
Tony     West  103.0         103.0
Sally   South  202.0         303.0
Carl     West    NaN         103.0
Archie  North    NaN           0.0
Randy    East  380.0         380.0
Ellen   South  101.0         303.0
Fred      NaN   82.0           NaN
Mo       East    NaN         380.0
HanWei    NaN    NaN           NaN

我们现在有了原始的 sales 列和一个新的 sales_region 列,它告诉我们一个地区的总销售额。让我们计算每个雇员占销售额的百分比,然后通过删除没有区域的观察值(弗雷德和韩伟)并用零填充销售列中的 NaNs 来清理我们的数据框架

In:# Drop NAs in region column
employee_contrib = employee_contrib.dropna(subset=['region'])# Fill NAs in sales column with 0
employee_contrib = employee_contrib.fillna({'sales': 0})employee_contrib['%_of_sales'] = employee_contrib['sales']/employee_contrib['sales_region']print(employee_contrib[['region','sales','%_of_sales']]\.sort_values(by=['region','%_of_sales'])) Out: region  sales  %_of_sales
Mo       East    0.0    0.000000
Randy    East  380.0    1.000000
Archie  North    0.0         NaN
Ellen   South  101.0    0.333333
Sally   South  202.0    0.666667
Carl     West    0.0    0.000000
Tony     West  103.0    1.000000

全部完成!请注意,北部地区没有销售额,因此有 NaN(不能被零除)。

结论

让我们快速回顾一下:

  • 我们可以使用 joinmerge 来合并 2 个数据帧。
  • 当我们在索引上连接数据帧时, join 方法效果最好(尽管您可以为左边的数据帧指定另一个要连接的列)。
  • merge 方法更加灵活,它允许我们指定索引之外的列来连接两个数据帧。如果索引在合并后被重置为计数器,我们可以使用 set_index 将其改回。

下一次,我们将了解如何通过 Pandas 的 concatenate 函数添加新的数据行(以及更多内容)。干杯!

如果你总体上喜欢这篇文章和我的写作,请考虑通过我的推荐链接注册 Medium 来支持我的写作。谢谢!T32

熊猫变得容易(指南)

原文:https://towardsdatascience.com/pandas-made-easy-the-guide-i-81834f075893?source=collection_archive---------36-----------------------

提供了一些最常用的函数和方法的例子。

照片由 Sid Balachandran 在 Unsplash 上拍摄

作为每个数据科学家都非常了解和使用的最受欢迎和最常用的工具之一, Pandas 库非常适合数据操作、分析和可视化,如果你经常练习,它应该很快就会在你的手指下流动。

为了帮助你完成这个任务并对你的 Python 编码更有信心,我用熊猫上一些最常用的函数和方法创建了这个指南。我真心希望这对你有用。

内容:

0.导入库
1。导入/导出数据
2。显示数据
3。基本信息:快速浏览数据
4。基本统计数据
5。调整数据
6。布尔索引:loc
7。布尔索引:iloc
8。基本处理数据

我们将致力于“泰坦尼克号”数据集,主要有两个原因:(1)很可能你已经熟悉它了,以及(2)它非常小,简单,并且有(也没有)我们举例说明所需的所有数据。

泰坦尼克号的数据集可以在这里下载。

0.导入库

对于我们的目的来说,‘熊猫’图书馆是我们起步的武器。

import pandas as pd

1.导入/导出数据

“泰坦尼克号数据集”与文章一起被指定为“数据”

a)使用read_csv将一个 csv 文件导入到笔记本中。您应该在文件中添加数据的分隔类型。

data = pd.read_csv("file_name.csv", sep=';')

b) 使用read_excel.excel 文件中读取数据

data = pd.read_excel('file_name.xls')

c) 导出数据帧到一个 csv 文件中使用to_csv,逗号分隔且不带索引。如果没有给定,则 header 和 index 为 True。

data.to_csv("file_name.csv", sep=';', index=False

d) 使用to_excel.数据帧导出到一个 excel 文件

data.to_excel("file_name.xls´)

2.显示数据

a) 打印第第‘n’行。如果没有给定,默认显示 5 行。

data.head()

作者图片

b) 打印最后‘n’行的**。下面显示了最后 7 行。**

data.tail(7)

作者图片

3.基本信息:快速浏览数据

a) 显示数据集的维度:行和列的总数。

data.shape (891,12)

b) 显示类型的变量

data.dtypes

PassengerId      int64
Survived         int64
Pclass           int64
Name            object
Sex             object
Age            float64
SibSp            int64
Parch            int64
Ticket          object
Fare           float64
Cabin           object
Embarked        object
dtype: object

c) 显示由排序的变量类型值。

data.dtypes.sort_values(ascending=True)

PassengerId      int64
Survived         int64
Pclass           int64
SibSp            int64
Parch            int64
Age            float64
Fare           float64
Name            object
Sex             object
Ticket          object
Cabin           object
Embarked        object
dtype: object

d) 计数变量型。

data.dtypes.value_counts()

object     5
int64      5
float64    2
dtype: int64

e) 计算每种类型的值,由命令值

data.dtypes.value_counts(ascending=True)

float64    2
int64      5
object     5
dtype: int64

f) 检查绝对值中幸存者与非幸存者数量之间的平衡

data.Survived.value_counts()

0    549
1    342
Name: Survived, dtype: int64

g) 检查特征的比例,占百分比

data.Survived.value_counts() / data.Survived.value_counts().sum()

...与以下内容相同:

data.Survived.value_counts(normalize=True)

0    0.616162
1    0.383838
Name: Survived, dtype: float64

h) 检查特征的比例,在百分比中,将四舍五入 4。

data.Survived.value_counts(normalize=True).round(decimals=4) * 100

0    61.62
1    38.38
Name: Survived, dtype: float64

i) 评估数据集中缺失值的存在。

data.isnull().values.any()

True

j) 使用isnull()变量的缺失值的数量。

data.isnull().sum()

PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64

k) 数量现有值使用notnull()

data.notnull().sum()

PassengerId    891
Survived       891
Pclass         891
Name           891
Sex            891
Age            714
SibSp          891
Parch          891
Ticket         891
Fare           891
Cabin          204
Embarked       889
dtype: int64

l) 百分比(%) 因变量而缺失的值。

data.isnull().sum() / data.isnull().shape[0] * 100

…等同于:

data.isnull().mean() * 100

PassengerId     0.000000
Survived        0.000000
Pclass          0.000000
Name            0.000000
Sex             0.000000
Age            19.865320
SibSp           0.000000
Parch           0.000000
Ticket          0.000000
Fare            0.000000
Cabin          77.104377
Embarked        0.224467
dtype: float64

m) 舍入小数值(在本例中为 2)。

(data.isnull().sum() / data.isnull().shape[0] * 100).round(decimals=2)

…等同于:

(data.isnull().mean() * 100).round(decimals=2)

PassengerId     0.00
Survived        0.00
Pclass          0.00
Name            0.00
Sex             0.00
Age            19.87
SibSp           0.00
Parch           0.00
Ticket          0.00
Fare            0.00
Cabin          77.10
Embarked        0.22
dtype: float64

n) 奖金 : 使用组合文本打印答案。

print("The percentage of 'Age' is missing values:",(data.Age.isnull().sum() / data.Age.isnull().shape[0] * 100).round(decimals=2), "%")

The percentage of 'Age' is missing values: 19.87 %

print(f"The feature 'Age' has {data.Age.isnull().sum()} missing values")

The feature 'Age' has 177 missing values

print("'Age' has {} and 'Cabin' has {} missing values".format(data.Age.isnull().sum(), data.Cabin.isnull().sum()))

'Age' has 177 and 'Cabin' has 687 missing values

o) 一般 形状、变量类型和缺失值的概述

data.info()

作者图片

p) 概述具体特征(下面例子中的‘性别’和‘年龄’)。

data[['Sex','Age']].info()

作者图片

4.基本统计

a)describe方法只给我们关于数据的基本统计。默认情况下,它将只计算数字数据的主统计。结果表示为熊猫数据框。

data.describe()

作者图片

b) 添加其他非标准值,例如‘方差’。

describe = data.describe()

describe.append(pd.Series(data.var(), name='variance'))

作者图片

c) 显示分类数据。

data.describe(include=["O"])

…等同于:

data.describe(exclude=['float64','int64'])

…也等同于:

data.describe(include=[np.object])

作者图片

d) 通过传递参数include='all',将同时显示数值和非数值数据。

data.describe(include='all')

作者图片

e) 不要忘记通过在末尾添加.T来转置数据帧。这也是适用于每个数据框的非常有用的资源。

data.describe(include='all').T

作者图片

f) 百分位数演算 1%、5%、95%、99%。正如所料,它将只计算数字特征的统计数据。

data.quantile(q=[.01, .05, .95, .99])

作者图片

g) 汇总统计数据

  • 显示某个特征的唯一值

data.Embarked.unique()

array(['S', 'C', 'Q', nan], dtype=object)
  • 计算某个特性的唯一值的总数**。**

data.Sex.nunique()

2
  • 计算的总值

data.count()

PassengerId    891
Survived       891
Pclass         891
Name           891
Sex            891
Age            714
SibSp          891
Parch          891
Ticket         891
Fare           891
Cabin          204
Embarked       889
dtype: int64
  • 某些特性的最高值

data.Age.max()

80.0
  • 某特性的最低值

data.Age.min()

0.42
  • 某些特征的平均值(平均值)。

data.Age.mean()

29.69911764705882
  • 某些特征的中值

data.Age.median()

28.0
  • 某些特征的第 99 个分位数

data.Age.quantile(q=[.99])

0.99    65.87
Name: Age, dtype: float64
  • 某些特征的标准偏差

data.Age.std()

14.526497332334044
  • 某些特征的差异

data.Age.var()

211.0191247463081

h) 奖金…

Q1——显示分类特征“已装船”中两个最常见的独特特征。

data[‘Embarked’].value_counts().head(2)

S    644
C    168
Name: Embarked, dtype: int64

Q2——已登船的最高独一无二的百分比是多少?(相对于所有其他部分而言,最常见的部分)。

top_unique = data['Embarked'].value_counts(normalize=True)[0]

print(f'{top_unique:.2%}')

72.44%

变量之间的相关性。正如所料,它将只显示数字数据的统计信息。

data.corr() #皮尔逊相关默认

作者图片

J)一个选择变量**(本例中为“存活”)与其他变量之间的相关性**。

correlation = data.corr()

correlation.Survived.sort_values().sort_values(ascending=False) #有序值

Survived       1.000000
Fare           0.257307
Parch          0.081629
PassengerId   -0.005007
SibSp         -0.035322
Age           -0.077221
Pclass        -0.338481
Name: Survived, dtype: float64

5.调整数据

a) 列出各列的名称。

data.columns

Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'], dtype='object')

b) 重命名某列(在下面的示例中,通过“Id”重命名“PassengerId”)。

data.rename(columns = {data.columns[0]:'id'}, inplace=True)

…等同于:

data.rename(columns = {'PassengerId':'id'}, inplace=True)

Index(['id', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'], dtype='object')

c) 重命名 几列 ('PassengerId ',' Pclass '和' SibSp ')。

data.rename(columns = {'PassengerId':'Passenger_Id', 'Pclass':'P_Class', 'SibSp':'Sib_Sp'}, inplace=True)

Index(['Passenger_Id', 'Survived', 'P_Class', 'Name', 'Sex', 'Age', 'Sib_Sp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'], dtype='object')

d) 通过列表理解用点代替 下划线(仅适用于‘乘客标识’,‘P _ Class’和‘Sib _ Sp’)。

data.columns = [x.replace('_', '.') for x in data.columns]

Index(['Passenger.Id', 'Survived', 'P.Class', 'Name', 'Sex', 'Age', 'Sib.Sp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'], dtype='object')

e) 降低上部字符去除 圆点(适用于‘乘客。Id ',' P.Class '和' Sib '。仅 Sp)。

data.columns = [x.lower().replace('.', '') for x in data.columns]

Index(['passengerid', 'survived', 'pclass', 'name', 'sex', 'age', 'sibsp', 'parch', 'ticket', 'fare', 'cabin', 'embarked'], dtype='object')

f) 列名大写。

data.columns = [x.capitalize() for x in data.columns]

Index(['Passengerid', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'Sibsp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked'], dtype='object')

6.布尔索引:loc

data.loc[<lines>, <columns>] #按职位和姓名选择

一)选择一排

data.loc[[3]]

作者图片

b) 选择一排 的行

data.loc[6:8]

作者图片

c) 选择几行

data.loc[[7,28,39]]

作者图片

d) 从几列‘姓名’、‘年龄’、‘性别’、‘幸存’中选择一行。

data.loc[[7], ['Name', 'Age', 'Sex', 'Survived']]

作者图片

e) 从几列中选择多行

data.loc[[7,28,39], ['Name', 'Age', 'Sex','Survived']]

作者图片

f) 选择特定值在某种条件下使用loc。在这种情况下,从第 4 行到第 10 行选择年龄大于或等于 10 岁的乘客。

data.loc[4:10, ['Age']] >= 10

作者图片

g) 选择特定值 s 在某种条件下使用loc。在这种情况下,从前 5 行中选择乘坐 C123 客舱的乘客。

data.loc[:4, ['Cabin']] == 'C123'

作者图片

7.布尔索引:iloc

data.iloc[<lines>, <columns>] #按位置和数字选择

a) 选择数据集的第一行

data.iloc[3]

作者图片

b) 从所有列中选择一个行数组

data.iloc[6:12]

作者图片

c) 从所有列中选择几行

data.iloc[[7,28,39],:]

作者图片

d) 从栏“姓名”、“年龄”、“性别”和“幸存”中选择一个行。

data.iloc[[7], [3,5,4,1]]

作者图片

e) 从几列中选择多行。

data.iloc[[7,28,39], [3,5,4,1]]

作者图片

f) 选择多行形成列的序列

data.iloc[[7,28,39], 3:10]

作者图片

g) 选择其他值

  • 从第 6 行到第 12 行,最后一列。

data.iloc[6:13, -1]

  • 第 3 列和第 6 列的所有行。

data.iloc[:, [3,6]]

  • 7,28,39 行,从第 3 列到第 6 列。

data.iloc[[7,28,39], 3:7]

  • 最后一列的最后 20 行。

data.iloc[-20:, -1:]

8.基本处理数据

  • Axis = 0,表示行,如果没有给定,则默认为 axis = 0。
  • Axis = 1,表示列。

作者图片

**a)**删除缺失值 (nan)。

data.isnull().values.any() #是否有数据缺失?

True

如果没有将它赋给一个(新的)变量,您应该指定inplace=True,这样任何更改都可以在同一个评估上生效。

data.dropna(axis=0, inplace=True) #从行中删除 nan

data.isnull().values.any() #有没有数据缺失?

False

b)移除立柱

data.drop(columns=['PassengerId', 'Name'], axis=1).head()

作者图片

c) 数值计数也可以显示 NaN 数值。

data.Age.value_counts(dropna=False)

NaN      177
24.00     30
22.00     27
18.00     26
28.00     25... 
36.50      1
55.50      1
66.00      1
23.50      1
0.42       1
Name: Age, Length: 89, dtype: int64

d) 替换缺失值(逐步)。

  • 创建一个新的数据帧,数据的副本 #以保持原始数据的完整性。

new_df = data.copy()

数据的平均值。年龄:

new_df.Age.mean()

29.69911764705882
  • 用数据的平均值填充任意 NAN。年龄并将结果分配给新列。

new_df['Age_mean'] = new_df.Age.fillna(new_df.Age.mean())

数据的中间值。年龄:

new_df.Age.median()

28.0
  • 用数据的中间值填充任何 NAN。年龄并将结果分配给新列。

new_df['Age_median'] = new_df.Age.fillna(new_df.Age.median())

  • 验证结果。

new_df[['Age', 'Age_mean', 'Age_median']].isnull().sum()

Age           177
Age_mean        0
Age_median      0
dtype: int64

显示第 106 至 110 行以验证两个 NAN 样本的插补(在第 107 和 109 行)。

new_df[['Age', 'Age_mean', 'Age_median']][106:110]

作者图片

已经累了?

乔希·威瑟斯在 Unsplash 上拍摄的照片

结论

我真诚地希望你发现这个指南是有用的,因为它可以对你的代码开发有所帮助。我将在未来更新它,并将其链接到其他 Python 教程。

请在下面的评论中发表你离不开的其他功能和方法,并强调它们。我想听听你的意见!

[## 机器学习:营销活动的成本预测(探索性数据分析——第一部分)

预测营销活动最佳目标候选人的数据科学方法

towardsdatascience.com](/machine-learning-costs-prediction-of-a-marketing-campaign-exploratory-data-analysis-part-i-758b8f0ff5d4) [## 营销活动的成本预测(数据清理和特征选择——第二部分)

预测营销活动最佳目标候选人的数据科学方法

towardsdatascience.com](/costs-prediction-of-a-marketing-campaign-data-cleaning-feature-selection-part-ii-6aa5298909b5)

联系人

  • Linkedin
  • 推特
  • 中等
  • GitHub
  • 卡格尔
  • 电子邮件

好的阅读,伟大的编码!

熊猫让 Python 变得更好

原文:https://towardsdatascience.com/pandas-makes-python-better-ec6cc1e30233?source=collection_archive---------14-----------------------

熊猫携带 Python 进行数据处理

我想谈论很久的一件事是熊猫给 Python 带来的力量。Pandas 是 Python 中数据科学的一个基本包,因为它功能多样,非常擅长处理数据。我非常喜欢熊猫的一个部分是它奇妙的 IPython 和 Numpy 集成。这就是说,熊猫是直接与 Numpy 交织在一起的,就像花生酱与果冻交织在一起一样。难怪这两种组合在一个完整的包装中一起出售。

抛开 Smucker 的 Goober 笑话不谈,Pandas 巧妙地让 Python 成为一种更可行的数据科学语言,仅仅是因为它内置于其中。这并不是说 Python 没有大量模拟这种确切效果的精彩包,因为 Python 有无数用于机器学习和数据处理的包。Pandas 使得相对困难的事情,或者在其他语言中比较痛苦的事情,在 Python 中变得非常简单。

IPython

支持熊猫的最大因素是——嗯,熊猫本身。该包从一开始就设计为包含 IPython 笔记本和 Numpy 等数据科学的主要产品。所有这些拼凑在一起的方式很有意义,但我不会告诉你这些,我将向你展示使用另一种语言的包是什么样子的,这是我最喜欢的:

朱莉娅

有趣的是,我们用来创建数据框的包是 DataFrames.jl。当然,我们现在将使用逗号分隔值文件(CSV 文件)。所以第一步是读入我们的数据…但是我们怎么做呢?在变更日志中,有一个叫做 read_table 的方法的简短提及,但是在大多数情况下,这似乎肯定是不赞成的。

这就是诀窍,为了用 DataFrames.jl 读入我们的 DataFrames,我们实际上必须得到另一个名为 CSV.jl 的包,添加这个包后,我们可以用 read()方法打开我们的 CSV 文件:

using CSV
df = CSV.read("Fizzbuzz")

太棒了,现在我们已经读取了我们的数据,但是我们在顶部得到了一个有趣的消息…

“省略打印 12 列”

很好,但是为什么呢?出于某种奇怪的原因,他们选择在 Iframe 之外呈现数据帧,根据特定的列长度省略列。那么我们如何显示所有的列呢?显示所有的列非常容易,只需向 show 方法添加一个 bool 类型的参数,如下所示:

等等,那是什么?没错,它会转到一个基于文本的数据框,并打印出列

在彼此之上。

好消息是,老 showall!()方法,这意味着当我们显示所有列时,不必显示所有行。这很可能是我不久前开始使用字典的原因…

好吧,现在我们知道这对朱莉娅来说有多难,但是熊猫呢?嗯,你不会认为它会这么简单,但是你需要的唯一的包是 Pandas,你需要的唯一的方法是 read_csv,最后,但同样重要的是,你可以使用函数 df.head()打印出你选择的头部长度,使用 df.tail()打印出你选择的尾部长度。更不用说,看起来是这样的:

相信我,R 的数据框架也没有 panda 好,而且大多数使用 R 和 Julia 的人倾向于 PyCall Pandas,而不是使用他们各自语言的数据框架包。

Numpy

umpy 是 Python 数据科学包三剑客的另一部分。Numpy 集成允许在数据框内使用 Numpy 的所有线性代数。此外,Numpy 的某些部分使数据处理变得更加容易。看看我一眨眼就销毁了一千多个空值!

重要的是要记住,鉴于 Python 是一种编程语言,普通 Python 和线性代数实际上并不像你想象的那样相处融洽。我认为这仅仅是因为 Python 比“线性代数”更高级,当然也不希望它成为许多公司现在深陷其中的统计语言。当然,我的 df.dropna()例子很简单,但是可以肯定的是,在某种程度上,与 Numpy 的紧密集成将使您的生活变得更加轻松!

熊猫本身

除了 Pandas 出色的集成和围绕其他 Python 包的方法论之外,Pandas 还有许多好处,这些好处是他们所做的所有出色的开源工作所提供的。每一个扭曲,每一个旋转,索引,连接,融合,旋转,甚至交叉制表都可以在熊猫的一行中完成。这些任务在其他包裹中确实可以提供一个完整小时的工作,但是用熊猫——它很容易而且即时。

通过 replace()函数这样的简单工具,使用 Pandas 变得更加容易,replace()函数可用于替换 nan,或者只是奇怪的数据。熊猫让很多工作变成了一点点工作,这就是它如此受欢迎和令人印象深刻的原因。但是熊猫还有更多巨大的好处。

字符串存取器

是的,传说是真的:

数据框被美化成字典。

但是并不是所有的字典都是一样的。首先,在我所知道的语言中,熊猫的条件掩蔽是迄今为止最好的。

在一个简单的步骤中,数据被完全过滤并准备就绪,所有这些都包含在 Pandas 中,而不需要实际运行任何额外的方法——因为毕竟,它只是一个字典。

Julia 也有字典,他们的 DataFrames.jl 包当然是完全相同的系统,但在我看来,在这种情况下,当它试图与熊猫站在一起时,它就彻底失败了。首先,为了使用布尔型遮罩,我们使用了过滤器!()方法。没问题,它有点不太优雅,但不管怎样,它工作得非常好。但是总的来说,在朱莉娅的字典中,有一个非常重要的问题很少被提及,这让我很惊讶。

Julia 的字典命名方案使用符号而不是字符串。这是一个很大的问题,因为我们所有键盘的底部都有一个邪恶的东西,

空格键。

如您所见,典型的字符串命名方案在 Julia 中不起作用。相反,Julia 使用的符号是通过在变量名前加一个冒号创建的。所以让我们用一个符号来代替:

好的,这是可行的,但是我们如何用一个空格来做这件事呢?这是个大问题,如果名称中有空格,就没有办法访问这个列,根本没有办法。当然,大多数数据框的列名中没有空格,因为使用 _ 比空格更合适,但是如果有呢?在 Julia 中唯一有意义的解决方案是打开 CSV 文件并更改其中的列名,这是一个大问题。

结论

我喜欢熊猫。

Pandas 是一个非常棒的包,它让数据科学在很大程度上变得非常容易。我当然希望 DataFrames.jl 可以模仿 Pandas 为 Python 数据科学社区所创造的东西。熊猫真正伟大的地方在于它周围的整个技术体系如何与它无缝衔接。

Python 世界当然是一个美丽的世界。

熊猫-mapper API

原文:https://towardsdatascience.com/pandas-mapper-api-2f93400d1dca?source=collection_archive---------39-----------------------

以及它与应用功能有何不同

公园巡警在 Unsplash 拍摄的照片

Pandas 是一个非常强大和通用的 Python 数据分析库,它加速了数据科学项目的预处理步骤。它提供了许多在数据分析中非常有用的函数和方法。

虽然 Pandas 的内置功能能够执行高效的数据分析,但定制的库或 API 为 Pandas 增加了价值。在本帖中,我们将探索其中的一个,那就是熊猫测绘员。

让我们从安装和导入开始。我们还需要进口熊猫,因为我们将在数据帧上工作。

pip install pandas-mapperimport pandas_mapper
import pandas as pd

Pandas-mapper 根据转换映射数据帧中的值。不如先做个例题,再解释语法。

考虑以下数据帧:

(图片由作者提供)

我们希望创建一个列来指示“col_c”中的字符串包含大写字母和小写字母。除了“pandas”和“STATS”之外的所有行都符合我们的描述。下面是我们如何用熊猫制图仪来完成这项任务。

df.mapping([('col_c', 'not_mix', 
lambda row: row.isupper() | row.islower())])

一旦安装了 pandas-mapper,我们就有了一个关于数据帧的新方法,即映射

第一个参数是元组列表,它依次包含源列、目标列和转换。

应用映射时,定义的映射完成。

df.mapping([('col_c', 'not_mix', 
lambda row: row.isupper() | row.islower())]).**mapped**

(图片由作者提供)

我们可以用映射返回的内容创建一个新列,或者使用 inplace 参数。

df.mapping([('col_c', 'not_mix', 
lambda row: row.isupper() | row.islower())], **inplace=True**).mapped

(图片由作者提供)

Pandas-mapper 也接受用户定义的函数作为转换。下面的代码块将获得相同的结果。

def not_mix(row):if row.isupper() | row.islower():return Falseelse:return Truedf.mapping([('col_c', 'mix_case', not_mix)], inplace=True).mapped

pandas-mapper 和 apply 函数的主要区别在于错误处理。

考虑一种情况,其中一个字符串列包含数字,我们需要基于字符串进行转换。

(图片由作者提供)

让我们尝试进行与上一步相同的转换。

mapper = df.mapping([('col_c', 'mix_case', not_mix)])df_transformed = mapper.mapped

我们出错了。 on_error 参数可用于处理此类错误。

mapper = df.mapping([('col_c', 'mix_case', not_mix)], **on_error**='redirect')df_transformed = mapper.mappeddf_transformed

任务在适当的行上完成。索引为 4 且不包含字符串的行保存在单独的数据帧中。我们可以使用错误方法来访问它。

(图片由作者提供)

到目前为止,我们一直致力于一对一的映射。Pandas-mapper 还支持一对多和多对多映射。

pandas 的功能丰富了第三方软件包,通过展示不同的方法和视角来改进数据分析过程。

用熊猫完成一项任务几乎总是有多种方式。例如,我们在这篇文章中做的一些事情也可以使用列表理解或 pandas 自己的字符串操作来完成。但是,最好知道其他替代方案,以防需要。

感谢您的阅读。如果您有任何反馈,请告诉我。

和达斯克一起在云上的熊猫

原文:https://towardsdatascience.com/pandas-on-the-cloud-with-dask-9451199b0226?source=collection_archive---------26-----------------------

使用 Dask 将 Pythonic 数据科学和机器学习扩展到云。所有这些都来自您自己的笔记本电脑。

Elena Mozhvilo 在 Unsplash 上的照片

在进行数据科学和/或机器学习时,需要将分析扩大到更大的数据集变得越来越常见。

在 Python 和 PyData 生态系统中工作时,Dask 是一个流行的工具。原因有很多,其中之一是 Dask 可以很好地与所有 PyData 工具兼容。这是一个简单的系统,旨在并行化任何 PyData 库。

当开始处理更大的数据集时,您首先会希望扩展您的分析,以利用单个工作站的所有内核。

在这之后,你可能需要横向扩展你的计算来利用云上的集群(例如,AWS、Azure 或 Google 云平台)。

在本帖中,我们

  • 使用熊猫演示数据科学工作流中的常见模式,
  • 展示我们如何使用 Dask 来利用单个工作站的内核,并
  • 展示我们如何使用盘绕云将其扩展至云。有许多向外扩展到云的解决方案,但我对 Coiled 特别感兴趣,因为我们刚刚发布了我们的云产品。

你也可以在 Github 上找到所有的代码。

注意:你应该总是试着思考你是否真的需要扩展你的计算。例如,在这样做之前,也许你可以让你的熊猫代码更有效。如果你在做机器学习,画出学习曲线,以确保包含更多的数据将真正导致改善你的模型。

熊猫:数据科学中的一种常见模式

在这里,我们介绍数据科学中的一个常见模式,并展示如何在内存数据集上使用 pandas 来执行它。我们将检查纽约出租车数据集的 700MB 子集(总共约 10 GB)。

我们读入数据,并使用 groupby DataFrame 方法检查平均小费金额,作为乘客人数的函数:

# Import pandas and read in beginning of 1st file 
import pandas as pd 
df = pd.read_csv("data_taxi/yellow_tripdata_2019-01.csv") # Compute average tip as a function of the number of passengers df.groupby("passenger_count").tip_amount.mean()

这在我的笔记本电脑上花了大约 15 秒,在我愿意等待我的分析的容忍时间内。

接下来,我想对整个数据集执行完全相同的分析。

DASK:扩展您的数据科学

回想一下,整个数据集大约有 10GB,这超过了我笔记本电脑上的可用 RAM,这意味着我无法将它存储在内存中。

我可以写一个 for 循环:

for filename in glob("~/data_taxi/yellow_tripdata_2019-*.csv"):df = pd.read_csv(filename)df.groupby("passenger_count").tip_amount.mean()

这没有利用我的笔记本电脑上的多个内核,也不是特别优雅。输入 Dask 表示单机并行度。

我们导入 Dask 的几个部分,启动一个本地集群并实例化一个 Dask 客户端:

from dask.distributed import LocalCluster, Client 
cluster = LocalCluster(n_workers=4) 
client = Client(cluster) 
client

然后,我们导入 Dask DataFrame,读入所有数据(延迟),并计算相同的 groupby,就像上面我们对 pandas 所做的那样。

import dask.dataframe as dddf = dd.read_csv("data_taxi/yellow_tripdata_2019-*.csv",dtype={'RatecodeID': 'float64','VendorID': 'float64','passenger_count': 'float64','payment_type': 'float64'}
)mean_amount = df.groupby("passenger_count").tip_amount.mean().compute()

这在我的笔记本电脑上需要大约 3.5 分钟,这是可以忍受的。我想是的。然而,如果你想做任何稍微复杂一点的事情(提示:你通常会做),这个时间会很快结束。

因此,如果我能够访问云上的集群,使用它将是一个好主意!

在此之前,让我们注意一下我们刚刚完成的几个方面:

  • 我们使用了 Dask 数据帧,它本质上是一个大的虚拟数据帧,沿着索引分成多个 Pandas 数据帧。
  • 我们正在研究一个本地集群,包括
  • 一个调度器(它管理并发送工作/任务给工人)和
  • 工人,他们计算任务。
  • 我们实例化了一个 Dask 客户端,“集群用户面向用户的入口点。”

这意味着,无论你在哪里编写 Python 代码,客户机都在那里,客户机与调度程序对话,把任务传递给调度程序。

盘绕:横向扩展您的数据科学

现在是时候奔向云了。如果您能够访问云资源(比如 AWS ),并且知道如何配置 Kubernetes 和 Docker 容器,那么您就可以在云中运行 Dask 集群。然而,这仍然需要大量的时间。

另一种方法是使用线圈,我们将在这里介绍。为此,我还登录了盘绕云,安装了盘绕 pip,并通过了身份验证。如果您想继续学习,可以在终端中自己完成这项工作

pip install coiled --upgrade
coiled login  # redirects you to authenticate with github or google

然后,我们执行必要的导入,启动一个集群(大约需要一分钟),并实例化我们的客户端:

import coiled
from dask.distributed import LocalCluster, Client
cluster = coiled.Cluster(n_workers=10)
client = Client(cluster)

然后我们可以导入我们的数据(这次是从 s3 ),并按以下方式执行分组:

import dask.dataframe as dd# Read data into a Dask DataFrame
df = dd.read_csv("s3://nyc-tlc/trip data/yellow_tripdata_2019-*.csv",dtype={'RatecodeID': 'float64','VendorID': 'float64','passenger_count': 'float64','payment_type': 'float64'},storage_options={"anon":True}
mean_amount = df.groupby("passenger_count").tip_amount.mean().compute()

在 Coiled Cloud 上,这一切只花了不到 30 秒的时间,比我在笔记本电脑上花的时间少了一个数量级,即使对于这个相对简单的分析也是如此。

请注意能够在单个工作流程中完成这组分析的强大功能。没有必要转换上下文或环境。最重要的是,在 Coiled 中,当我们完成后,可以直接在我的本地工作站或 pandas 上使用 Dask。云计算在必要时很棒,但在不必要时会成为负担。

你需要更快的数据科学吗?

您也可以立即开始使用盘绕式集群。Coiled 还处理安全性、conda/docker 环境和团队管理,因此您可以继续研究数据科学。今天就在卷云上免费开始吧。

原载于 2020 年 9 月 23 日https://coiled . io

熊猫支点——终极指南

原文:https://towardsdatascience.com/pandas-pivot-the-ultimate-guide-5c693e0771f3?source=collection_archive---------4-----------------------

你一直想知道但不敢问的关于熊猫的一切。

克里斯蒂安·弗雷南在 Unsplash 上拍摄的照片

andas pivot 是每个数据科学家的必备工具。有些人每天都使用它,有些人避免使用它,因为它看起来很复杂。我在后一组呆了很长时间。在我花时间做了一些研究后,我觉得我浪费了很多时间来编写不必要的代码。令我惊讶的是,我已经知道熊猫的主要组成部分了。这比看起来要简单。

这里有几个你可能会感兴趣的链接:

- [Complete your Python analyses 10x faster with Mito](https://trymito.io/) [Product]- [Free skill tests for Data Scientists & ML Engineers](https://aigents.co/skills) [Test]- [All New Self-Driving Car Engineer Nanodegree](https://imp.i115008.net/c/2402645/1116216/11298)[Course]

你愿意阅读更多这样的文章吗?如果是这样,你可以点击上面的任何链接来支持我。其中一些是附属链接,但你不需要购买任何东西。

什么是数据透视表?

数据透视表是一个统计表,它汇总了一个更广泛的表中的数据。实际上,数据透视表是根据值的细分来计算统计数据的。对于第一列,它将值显示为行,第二列显示为列。

让我们来看一个数据透视表的例子,它根据水果和顾客的分类来计算总和统计:

左边的表是右边数据透视表的基表。

我如何能在熊猫里旋转一张桌子?

Pandas 有一个 pivot_table 函数,它在数据帧上应用透视。它还支持 aggfunc,该函数定义旋转时要计算的统计数据(aggfunc 默认为 np.mean,它计算平均值)。我在下面的例子中使用总和。

让我们定义一个数据帧并应用 pivot_table 函数。

df = pd.DataFrame({"fruit": ["apple", "orange", "apple", "avocado", "orange"],"customer": ["ben", "alice", "ben", "josh", "steve"],"quantity": [1, 2, 3, 1, 2],}
)

我想有一个水果行(指定索引)和列(指定列)的客户细分。对于每一项,我想计算数量的总和。结果与上表相同。

df.pivot_table(index="fruit", columns="customer", values="quantity", aggfunc=np.sum)

为什么我在透视时得到一个值错误?

Gif 来自 giphy

最可能的原因是您使用了 pivot 函数而不是 pivot_table。这让我困惑了很多次。Pandas pivot 函数是一个功能不太强大的函数,它不需要聚合就可以处理非数字数据。

出现错误“值错误:索引包含重复条目,无法重新整形”,因为您的 DataFrame 中有重复条目。如果我要透视上面的数据帧,我会得到同样的错误,因为 apple 和 ben 是重复的,并且透视函数不聚合。

当我浏览 pivot 函数的 pandas 源代码时,它帮助我理解了这个问题。基本上,它的功能与下面的命令相同:

df.set_index(["fruit", "customer"])["quantity"].unstack()

旋转时实际上发生了什么操作?

Gif 来自 giphy

起初,旋转对你来说似乎是一个难以理解的概念。但是如果我告诉你你一直都在使用它——至少是熊猫旋转的核心命令。让我们看看下面的命令:

df.groupby(['fruit', 'customer']).quantity.sum().unstack()

你在熊猫用过 groupby 功能吗?sum 命令呢?什么事?我想是的。上述命令的输出与 pivot_table 的输出相同。

我没有多次使用过拆分,但它基本上可以将多索引拆分成列,如下图所示

拆垛操作

如何将缺失值设置为 0?

不要再说了!pivot_table 有一个 fill_value 参数来替换缺少的值。默认情况下没有。让我们试一试。

df.pivot_table(index="fruit", columns="customer", values="quantity", aggfunc=np.sum, fill_value=0)

我可以同时计算多个统计数据吗?

pivot_table 函数的参数 aggfunc 采用函数列表。让我们用和与平均来试试。

df.pivot_table(index="fruit", columns="customer", values="quantity", aggfunc=[np.sum, np.mean], fill_value=0)

我可以同时聚合多个值吗?

Gif 来自 giphy

你可以!与 aggfunc 参数类似,values 参数接受列名列表。让我们给数据框架添加一个价格列。

df['price'] = [0.1, 0.2, 0.1, 0.4, 0.15]

现在我们有两列值,让我们应用 pivot_table 函数:

df.pivot_table(index="fruit", columns="customer", values=["quantity", "price"], aggfunc=np.mean, fill_value=0)

我可以进一步细分行/列吗?

答案还是肯定的。参数 index 和 column 都采用列表。让我们将水果的来源列添加到数据框架中。

df['origin'] = ['italy', 'spain', 'spain', 'mexico', 'portugal']

现在,让我们按行和按列对水果和产地进行细分。

df.pivot_table(index=["fruit", "origin"],columns=["customer"],values=["quantity"],fill_value=0,aggfunc=np.mean,
)

它就像一个魔咒!

在你走之前

在 Twitter 上关注我,在那里我定期发布关于数据科学和机器学习的消息。

照片由Courtney hedge在 Unsplash 拍摄

熊猫图谱——一个强大的探索性数据分析工具

原文:https://towardsdatascience.com/pandas-profiling-a-powerful-exploratory-data-analysis-tool-9c245079be4?source=collection_archive---------49-----------------------

只用一行代码就可以快速浏览您的数据

照片由 Sid Balachandran 在 Unsplash 上拍摄

介绍

在获得用于分析的新数据集之后,第一步是理解数据,例如,理解数据类型、唯一值的数量、缺失值、数据的分布等..

Pandas 提供了一些有用的函数,比如用info()获得数据集的概览,summary()获得数值变量的汇总,nunique()获得唯一值的数量,hist()检查分布,等等。每当我们得到一个新的数据集时,人们都必须做这种多步骤的工作。

Pandas-profiling是一个强大的工具,只需一行代码就能使 EDA 过程变得容易得多。它分析数据集—结合多个步骤,并创建一个交互式 HTML 报告。

熊猫-侧写

首先,我们需要安装软件包。

!pip install -U pandas-profiling[notebook]

这里我将使用一个提示数据集作为例子。一旦我们加载了数据集,通常我们会打印出几行来检查数据。

并使用info()来大致了解数据结构。

然后通常检查其他函数,例如重复、缺失值、唯一值、分布、统计等。

pandas_profiling 中,这些 EDA 步骤可以简化为一个步骤。

from pandas_profiling import ProfileReportprofile = ProfileReport(df, title='Pandas Profiling Report')

然后使用:

profile.to_widgets()

以生成报告。这将在 Juypter notebook 中创建一个交互式小部件。

或者您可以使用:

profile.to_notebook_iframe()

做出这样的 HTML 报告。您将获得数据的概述:

变量分析:

直方图,以及离群值。

它还检查变量之间的相互作用和相关性:

如有必要,您可以保存 HTML。

profile.to_file(output_file="pandas_profiling.html")

结论

总的来说,在数据分析的开始阶段快速了解数据集是一个有用的工具。它在一行代码中结合了我们通常使用纯熊猫所采取的步骤。

感谢阅读,我希望你喜欢这个工具。

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

[## 熊猫中的数据可视化

仅使用熊猫进行快速数据可视化

towardsdatascience.com](/data-visualization-in-pandas-2a7898e65114) [## 让我的数据分析过程更高效的 10 个熊猫窍门:第二部分

我希望我早点知道的技巧

towardsdatascience.com](/10-pandas-tricks-to-make-my-data-analyzing-process-more-efficient-part-2-b72ea43a0bb5) [## 让我的数据分析过程更高效的 10 个熊猫窍门:第 1 部分

我希望我早点知道的技巧

towardsdatascience.com](/10-pandas-tricks-to-make-my-data-analyzing-process-more-efficient-part-1-78a0cc1636f3) [## 让我的代码更好更聪明的 7 个小技巧

我希望我早点知道的技巧

towardsdatascience.com](/7-numpy-tricks-to-make-my-code-better-and-smarter-9e8a4ccf43d1) [## 让我的代码更好更聪明的 7 个 Python 技巧。

我希望我能早点知道的技巧。

towardsdatascience.com](/7-python-tricks-to-make-my-code-better-and-smarter-60dfde0b6c49)

熊猫概况和探索性数据分析的第一行代码!

原文:https://towardsdatascience.com/pandas-profiling-and-exploratory-data-analysis-with-line-one-of-code-423111991e58?source=collection_archive---------17-----------------------

了解如何为自动 EDA 安装和使用 pandas profiling

科林·伯伦斯来自的图片

简介

如果你已经熟悉熊猫概况包,你不会从这篇文章中学到任何新东西,所以你现在可以跳过它。

然而,如果你从未听说过它,这可能是迄今为止你得到的关于数据分析的最好的生产力提示之一,所以坚持住。

熊猫简介

Pandas profiling 是一个包,它允许您用最少的努力创建一个探索性的分析数据报告,一行代码。

因此,如果您是一名数据科学家或分析师,一直在手动进行探索性数据分析,那么使用 pandas profiling 将为您节省大量时间、精力和打字。你还记得做探索性数据分析时使用的所有重复代码吗,比如:

info(),

描述(),

isnull(),

corr(),

等等。

你不用再做了。Pandas profiling package 将为您完成这项工作,并为您的数据创建一份完整的摘要报告。

所以让我们开始吧!

如何安装熊猫评测包

熊猫档案的安装非常容易。您可以使用标准的 pip 命令。

pip install pandas-profiling

安装这个包需要一两分钟的时间,你应该已经准备好在 python 中使用 pandas profiling 了。

如何创建分析报告

为了创建报告,您可以使用标准的 read_csv()函数加载数据集,该函数将数据存储在 pandas 数据框中。

然后使用 ProfileReport 初始化器,并向它传递一个刚刚创建的数据帧作为参数。

您可以使用 to_file()函数来导出报告,以便进行检查。

import pandas as pd
from pandas_profiling import ProfileReportdf = pd.read_csv(data_file_name)report = ProfileReport(df)report.to_file(output_file='output.html')

我们来看一个真实的例子。

我们将为真实数据集创建一个报告。我们选择了一个关于心脏病的数据集,可以从这里下载。这个数据集大小为 33 KB,有 14 列,303 个观察值。

让我们使用 pandas profiling 为这个数据集创建一个报告。

from pandas_profiling import ProfileReportdf = pd.read_csv('heart.csv')report = ProfileReport(df)report.to_file(output_file='output.html')

运行这段代码后,您应该会看到报告生成的进度条,在几秒钟内,您应该能够通过在浏览器中打开output.html文件来查看完整的报告。

是的,就是这么简单!报告准备好了,你可以看了!

** * 报告应保存在读取原始数据的同一文件夹中。

报表结构

让我们看看熊猫概况报告中包含了什么。

  • 概述

在概述部分,我们应该看到三个选项卡:概述再现警告

概览选项卡给出数据的基本信息,如列数和行数、数据大小、缺失值百分比、数据类型等。

再现包含关于报告创建的信息。

警告选项卡包括生成报告时触发的警告。

  • 变量

本节重点对每个变量进行详细分析。

如果变量是连续的,它将显示一个直方图,如果是分类的,它将显示一个带有值分布的条形图。

您还可以看到每个变量缺失值的百分比。

下图显示了对心脏病数据集的年龄性别变量的分析。

  • 互动

交互作用部分关注数值变量之间的二元关系。您可以使用选项卡来选择要检查的关系对。下图是年龄胆固醇的关系。

  • 相关性

本节显示了不同类型的相关性。您可以查看数字变量的 Pearson、Spearman、Kendall 和 Phik 相关以及分类变量的 Cramer V 相关的报告。

  • 缺失值

这一部分显示列分解后数据集中缺失的值。

我们可以看到我们的数据集在 my 的列中没有丢失值。

  • 样品

这是一个取代手工数据分析的 head()和 tail()函数的部分。您可以看到数据集的第一行和最后 10 行。

  • 重复行

此部分显示数据集中是否有重复的行。在心脏病数据集中实际上有一个重复的条目,其细节显示在下面的截图中。

缺点

在这篇文章中,我们已经谈了很多关于熊猫概况包的优点,但有任何缺点吗?是的,我们来提一些。

如果您的数据集非常大,创建一个报告需要很长时间(在极端情况下可能需要几个小时)。

我们有一些使用概要分析包的基本 EDA,这是数据分析的良好开端,但它肯定不是一个完整的探索。通常我们会看到更多的图形类型,如箱线图、更详细的条形图,以及一些其他类型的可视化和探索技术,它们将揭示特定数据集的古怪之处。

此外,如果您刚刚开始您的数据科学之旅,可能值得学习如何使用 pandas 本身收集报告中包含的信息。这是为了让你练习编码和操作数据!

否则,我认为它是一个伟大的和非常有用的包!

总结

在本文中,我们向您展示了如何安装和使用 pandas profiling。我们甚至向您展示了对结果的快速解释。

下载心脏病数据集自己试试。

最初发布于 aboutdatablog.com: 熊猫剖析和探索性数据分析,代码第一行!,2020 年 6 月 6 日。

PS:我正在 Medium 和aboutdatablog.com上撰写深入浅出地解释基本数据科学概念的文章。你可以订阅我的 邮件列表 以便在我每次写新文章时得到通知。如果你还不是中等会员,你可以在这里加入

下面还有一些你可能喜欢的帖子

* [## 9 熊猫有效数据分析的可视化技术

学习如何使用折线图、散点图、直方图、箱线图和其他一些可视化技术

towardsdatascience.com](/9-pandas-visualizations-techniques-for-effective-data-analysis-fc17feb651db) [## python 中的 lambda 函数是什么,为什么你现在就应该开始使用它们

初学者在 python 和 pandas 中开始使用 lambda 函数的快速指南。

towardsdatascience.com](/what-are-lambda-functions-in-python-and-why-you-should-start-using-them-right-now-75ab85655dc6) [## Jupyter 笔记本自动完成

数据科学家的最佳生产力工具,如果您还没有使用它,您应该使用它…

towardsdatascience.com](/jupyter-notebook-autocompletion-f291008c66c)*

熊猫简介& Sweetviz

原文:https://towardsdatascience.com/pandas-profiling-sweetviz-8849704cadd7?source=collection_archive---------46-----------------------

Python EDA 工具有助于 EDA

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

D 数据清理和探索性数据分析齐头并进——通过更好地理解数据,可以更好地发现错误或异常值以进行缓解。

我们大多数人通过 pandas 函数做 EDA,再加上使用 matplotlib 到 seaborn 的可视化。有时,我们定义函数来执行 1)自动化和 2)定制的数据集 EDA(例如,在合并多个大型数据集之前对它们执行 EDA)。在为一个 pet 项目处理相关矩阵时,我偶然发现了 Sweetviz & Pandas 分析,并将它们纳入了我的 EDA 工作流。以下是一些观察结果:

熊猫简介

兼容性和安装:厌倦了潜在的兼容性问题,一个快速的 google/ StackOverflow 搜索浮出了 pandaspandas profiling版本之间的问题。对我有用的版本有 熊猫(1.0.1)熊猫简介(2.4.0) 。如果 pandas profiling and upgrade 的缺省安装无法通过 anaconda navigator 正常工作,请尝试:

conda install -c conda-forge/label/cf202003 pandas-profiling

输出:查看输出有两种方法— 1 .jupyter 笔记本本身或 2 中的交互式小部件。HTML 格式(允许在笔记本外部查看)。HTML 格式在内容和布局上本质上是一样的。

Pandas profiling 从数据集的概述开始,然后是变量的统计信息(按字母顺序)。相关性矩阵位于相关性选项卡下。缺失值(如果有)在图中用空白标记——类似于 缺失号 包。

熊猫简介概述(图片由作者提供)

Sweetviz

兼容性和安装:安装可通过 pip install 获得,非常简单。它支持 Python 3.6+和 Pandas 0.25.3+,尽管对 Google Colab 的支持还不可用。

输出:Sweetviz 默认生成一个 HTML 报告。这意味着预测变量到目标变量的快速可视化。Sweetviz 输出可视为左右面板显示器。顶部的左侧面板显示顶级数据集特征(例如,数据集中的观测值数量、特征(变量)数量、副本(如果有)),后面是各个变量的深入汇总统计数据。

右侧面板显示了对变量间关系(皮尔逊相关)和值分布的更深入的分析。在此空间下可以找到按数字和分类类型对变量进行的分组(不确定 sweetviz 是否可以自动识别分类特征)。

要在变量之间导航,单击变量,会出现一个红色的边界框,将右侧面板显示“锁定”在适当的位置。再次取消选择以继续其他变量。

sweetviz 的一个有趣特性是它的汇总关联图,其中区分了分类变量和数值变量。在我的个人项目中,如果变量被正确编码,它可以作为一个快速的完整性检查。对于较大的数据集,这可能是筛选变量的快速直观帮助。

Sweetviz 关联图(图片由作者提供)

哪个对 EDA 更好?

这取决于读者的需求和个人喜好。由于这是我第二次涉足这两个库,我花了大部分时间将我自己对 EDA 的见解与这两个库的输出进行比较。就我个人而言,我仍然更喜欢通过自定义函数来完成自己的 EDA,然后使用其中一个库进行快速复查。pandas profiling 和 sweetviz 都在一定程度上自动化和加速了 EDA 过程(减少了初始安装故障排除),并提供了对数据集特征的快速洞察。

对于初学者来说,在尝试 pandas profiling 和/或 sweetviz 之前,最好先了解一下用于 EDA 的 pandas 函数。依我看,更重要的是具备基本的统计知识来很好地解释输出,以便充分利用这些图书馆的潜力。

我希望这篇文章是一篇信息丰富的文章。下次再见,干杯。

熊猫:收起新手数据分析师的身份(第 1 部分)

原文:https://towardsdatascience.com/pandas-put-away-novice-data-analyst-status-part-1-7e1f0107dae0?source=collection_archive---------27-----------------------

熊猫如何让你成为更好的数据分析师?了解数据分析过程中不同步骤的一行程序。

芝扬在上拍照

我称之为熊猫PutAwayNoviceDATAAanalystStatus 是一个强大的开源数据分析和操作库。它可以帮助您对数据进行各种操作,并生成不同的报告。我要把它分成两篇文章-

  1. 基础知识——我将在这个故事中讲述。我将介绍熊猫的基本功能,这些功能将向您概述如何开始使用熊猫,以及它如何帮助您节省大量时间。
  2. 高级-引导您使用高级功能,轻松解决复杂的分析问题。它涵盖了样式、绘图、数据透视表等主题。务必检查第二部分。

[## 熊猫:收起新手数据分析师的身份(第 2 部分)

了解如何使用新冠肺炎数据绘制、设计、多索引或透视您的熊猫数据框架。

towardsdatascience.com](/pandas-put-away-novice-data-analyst-status-part-2-8df616d5ac7c)

在文章结束时,你应该能够回答以下问题—

  1. 如何读取不同格式的数据?
  2. 使用不同 API 的数据探索。
  3. 数据维度是什么。
  4. 如何查找数据汇总?
  5. 如何检查关于数据的不同统计?
  6. 如何选择数据子集?
  7. 一个线性来计算每个值的频率的唯一值。
  8. 如何根据条件过滤数据?
  9. 以不同格式保存数据。
  10. 使用链接应用多个操作。

开始之前,请确保您已经安装了熊猫。如果没有,您可以使用下面的命令下载它。

# If you are using Anaconda Distribution (recommended)
conda install -c conda-forge pandas# install pandas using pip
pip install pandas# import pandas in notebook or python script
import pandas as pd

如果您还没有为您的数据分析或数据科学项目设置环境,您可以参考我的博客“如何开始您的数据科学之旅”,它将带您了解您可以使用的不同库以及如何安装它们。

在这个练习中,我将使用著名的泰坦尼克号数据集。我推荐你从 Github 下载数据和笔记本。将其复制到您的环境中,并遵循它。

[## ankitgoel 1602/数据科学

熊猫:收起新手数据分析状态。这个库给出了你可以使用的不同熊猫 API 的概述…

github.com](https://github.com/ankitgoel1602/data-science/tree/master/data-analysis/pandas)

关于数据的更多细节,可以参考 Kaggle 。

让我们开始,我试图保持数据分析的一般流程,就像从读取数据开始,然后经历数据分析过程中的不同步骤。

1.使用 read_csv 或 read_excel 或 read_json 读取数据

任何数据分析的起点都是获取数据集。Pandas 提供不同的功能来读取不同格式的数据。最常用的是—

read_csv()

这允许您读取 CSV 文件。

pd.read_csv('path_to_your_csv_file.csv')

Pandas 提供了不同的选项来配置列名、数据类型或您想要读取的行数。查看熊猫 read_csv API 了解更多详情。

熊猫提供了不同的 read_csv 选项。来源- 熊猫文献。

read_excel()

这允许您读取 Excel 文件。

pd.read_excel('path_to_your_excel_file.xlsx')

像 CSV 一样,Pandas 为 read_excel 提供了一组丰富的选项,允许您读取 excel 中特定的工作表名称、数据类型或要读取的行数。查看 Pandas read_excel API 了解更多细节。

read_json()

Pandas 的这个 API 有助于读取 JSON 数据,对于已经扁平化的数据非常有用。让我们以一个 JSON 为例,看看如何将它转换成平面表。

# Sample Record: Flattend JSON i.e. no nested array or dictionary
json_data = {"Scaler": "Standard","family_min_samples_percentage": 5,"original_number_of_clusters": 4,"eps_value": 0.1,"min_samples": 5,"number_of_clusters": 9,"number_of_noise_samples": 72,
}# reading JSON data
pd.read_json(json_data)

只是看了 JSON 就把它转换成了下面的平面表。

当 JSON 数据是半结构化的,即包含嵌套的列表或字典时,它就不能很好地工作。Pandas 确实为此提供了一个 API json_normalize,如果你想了解更多,请查看

[## 如何用 Python 熊猫解析 JSON 数据?

使用 Pandas 读取 JSON 数据并将其规范化为平面表的一行程序。

towardsdatascience.com](/how-to-parse-json-data-with-python-pandas-f84fbd0b1025)

不仅如此,Pandas 还支持许多其他数据类型。如果您使用其他数据类型,请务必查看 Pandas 文档。

使用 read_csv 命令读取我们将在这里使用的 titanic 数据集-

# You can get it from the Github link provided.# Loading Titanic Dataset into titanic_data variable
titanic_data = pd.read_csv('titanic_train.csv')

这将创建一个 Pandas 数据帧(类似于表)并将其存储到 titanic_data 变量中。

接下来,我们将看到如何获得关于我们加载的数据的更多细节。

2.使用头部、尾部或样本浏览数据。

一旦我们加载了数据,我们想审查它。熊猫提供了不同的 API,我们可以用它们来探索数据。

头部( )

这就像 SQL 中的 TOP 命令,从数据帧的开始给我们“n”条记录。

# Selecting top 5 (n=5) records from the DataFrame
titanic_data.head(5)

泰坦尼克号数据集中的前 5 条记录。来源:作者。

尾部( )

这为我们提供了从数据帧末尾开始的“n”条记录。

# Selecting last 5 (n=5) records from the DataFrame
titanitc_data.tail(5)

泰坦尼克号数据集中的最后 5 条记录。来源:作者。

样本( )

这将从数据中随机选取“n”条记录。注意-在不同的运行中,该命令的输出可能会有所不同。

titanic_data.sample(5)

泰坦尼克号数据集中的 5 条随机记录。来源:作者。

3.使用形状的数据维度

一旦我们有了数据,我们需要知道我们正在处理多少行或列,而 Pandas shape API 正好给了我们这些。让我们看看—

# shape of the dataframe, note there is no parenthesis at the end as it is a property of dataframe
titanic_data.shape(891, 12)

(891,12)意味着我们的 Titanic 数据集中有 891 行和 12 列。

4.使用 info()的数据汇总

让我们先看看它的输出——

titanic_data.info()

泰坦尼克号数据集的信息。来源:作者。

正如你所看到的,“信息”提供了我们所拥有的数据的一个很好的总结,让我们一个一个地理解它。

  1. 索引细节 Pandas 中的每个数据帧都有一个索引,如果你熟悉 SQL,它基本上就像是我们为访问数据而创建的索引。这意味着我们有一个从 0 到 890 的 RangeIndex,即总共 891 行。
  2. 由“info”生成的表中的每一行都向我们提供了关于我们拥有的列的详细信息,列中有多少个值,以及 pandas 分配给它的数据类型。这有助于了解丢失的数据,比如我们可以说我们只有 714 行的“年龄”数据。
  3. 内存使用——Pandas 将数据帧加载到内存中,这告诉我们数据集使用了多少内存。当我们有大型数据集时,这很方便,因此熊猫有一个特定的 API“memory _ usage”来提供更多选项。

5.使用 describe()的数据统计

这为我们提供了关于数据集的统计数据。如你所见,我们下面的数据显示—

在泰坦尼克号数据集上描述。来源:作者。

如您所见,它为我们提供了每列的大量信息,如记录数(不包括您在 Age 中看到的缺失记录)、平均值、标准差、最小值和不同的分位数百分比。默认情况下,该命令提供关于数字数据类型(如 int 或 float)的信息。要获得关于我们的“对象”列的统计信息,我们可以运行-

# show stats about object columns
titanic_data.describe(include=['O'])

有关 DataFrame 中对象类型列的详细信息。来源:作者。

如果你注意到了,我们在描述 API 中添加了“包含”参数,这是一个列表,我们可以传递多个值,比如-

  • include=['O ',' int64 ']-将给出有关数据帧中 Object 和 int 64 类型列的统计信息。
  • include=['O ',' float64 ']-将给出有关数据帧中 Object 和 float 64 类型列的统计信息。

与“include”类似,我们也可以使用“exclude ”,这将在计算统计数据时排除列类型。如果你对更多细节感兴趣,请参考熊猫文档。

6.使用 loc 和 iloc 进行数据选择

这些都是非常有用的功能,可以帮助我们进行数据选择。使用这些我们可以选择数据的任何部分。为了更好地理解它,让我们更改数据的索引(如果您不理解,请不要担心,我将在第 2 部分中讲述这一点)。

# Change index of our DataFrame from RangeIndex to 'Ticket' values
titanic_ticket_index = titanic_data.set_index('Ticket')

新索引为“票证”的数据帧。来源:作者。

loc()

这将根据标签(即列和行的名称)选择数据。比如上面的数据,行标签像 A/5 21171,PC17599,113803,列标签像 PassengerId,Survived,Sex。loc 的一般语法是—

dataframe_name.loc[row_labels, column_labels(optional)]

Row_labels 和 columns_labels 可以采用不同的值。让我们看一些例子来更好地理解它。

选择单个行。

输入您想要的行的标签,即我们是否要选择“票证”,其中值为“A/5 21171”。

# notice we need to use [] brackets# This returns the data for the row which matches the name.
titanic_ticket_index.loc['A/5 21171']

选择多行

很多时候,我们需要选择多行来进一步分析。的。loc API 可以获取您想要选择的 row_labels 列表,即

或者像—

# we can supply start_label:end_label
# here we are selecting rows from label 'PC 17599' to '373450'
titanic_ticket_index.loc['PC 17599':'373450']

来源:作者。

注意-如果多行具有相同的标签,这将不起作用。

选择单列

这类似于我们选择行的方式,但是在选择列时,我们需要告诉 Pandas 我们想要选择的行。我们可以使用“:”来代替 row_label,这意味着我们希望选择所有行。

# selecting Embarked column for all rows.
titanic_ticket_index.loc[:,'Embarked']

选择多列

类似于我们对多行所做的,只需要告诉熊猫我们选择了哪些行。

# Selecting Sex, Age, Fare, Embarked column for all rows.
titanic_ticket_index.loc[:,['Sex','Age','Fare','Embarked']]

或者像—

# we can supply column start_label:end_label
# here we are selecting columns from label 'Sex' to 'Embarked'
titanic_ticket_index.loc[:, 'Sex':'Embarked']

选择特定的行和列

我们可以组合行和列上的选择来选择特定的行和列

iloc()

这与 loc 类似,但是基于索引而不是标签来选择行和列。与标签不同,索引对于行总是从 0 到 number_of_rows-1 开始,对于列总是从 0 到 number_of_columns-1 开始。

让我们看一个例子-

# selecting specific rows and columns: example 2
# we can use start_index:end_index for both columns and rows.# selecting 3rd to 6th row and 1st to 4th column 
# end_index should be 1 greater the row or column number you want
titanic_ticket_index.iloc[3:7, 1:5]

在这里,我们没有像对“loc”那样浏览示例。如果你想了解我们如何使用通过 loc API 获得的 iloc 实现同样的结果,你可以参考 Github 。如果你在应用时遇到任何困难,请在评论中告诉我。

7.使用 value_counts()的列中的唯一值

Value_counts 给出了列中唯一值的计数,这对于了解以下信息非常有用

  • 列中有不同的值。
  • 最常见的值。
  • 最频繁值的比例。
# value counts for the Sex column.
titanic_data['Sex'].value_counts()# output
male      577
female    314
Name: Sex, dtype: int64

如你所见,我们的数据集包含了更多的男性。我们甚至可以将其标准化,以查看值之间的分布。

# value counts normalized for Sex column
titanic_data['Sex'].value_counts(normalize=True)#output
male      0.647587
female    0.352413
Name: Sex, dtype: float64

这意味着,在我们的数据集中,男性和女性的比例大约是 65:35。

8.使用 query()过滤数据

通常,我们处理难以分析的大型数据集。在这种情况下,策略是过滤不同条件下的数据并进行分析。使用 Pandas Query API,我们只用一行代码就可以做到这一点。

让我们举几个例子来更好地理解它。

选择年龄为> 15 的行。

# first 5 records that has Age > 15
titanic_data.query('Age > 15').head(5)

选择幸存的雄性。

# first 5 males who survived
titanic_data.query('Sex=="male" and Survived==1').head(5)

我们可以定义变量并使用它们来编写过滤查询。当我们需要写脚本时,它会很方便。

# gender to select and min_fare, these can be passed as part of argument to the Script
gender_to_select = "female"
min_fare = 50# querying using attribute passed
titanic_data.query('(Sex==@gender_to_select) and (Fare > @min_fare)')

9.使用 to_csv 或 to_excel 保存数据

一旦我们在选择或过滤后得到了所需的数据,我们需要将它保存到

  • 与他人分享。
  • 在另一个笔记本中使用它。
  • 使用一些工具将其可视化。

像读取数据一样,Pandas 提供了不同的选项来保存数据。我将介绍两个常用的主要 API。您可以参考 Pandas 文档以获得保存数据的其他格式。

to_csv()

这允许您保存到 CSV 文件。

# Save data for males who survived into CSV file
males_survived = titanic_data.query('Sex=="male" and Survived==1')# Saving to CSV, index=False i.e. do not write Index.
males_survived.to_csv('males_survived.csv', index=False)

到 excel()

这允许您保存到 Excel 文件。熊猫需要安装 Openpyxl 包。如果你没有它,安装它使用—

# If you are using Anaconda Distribution (recommended)
conda install -c conda-forge openpyxl# install openpyxl using pip
pip install openpyxl

让我们保存到一个 Excel 文件—

# Save the data for passengers travelling with a Sibling or Parent
passengers_not_alone = titanic_data.query('SibSp==1 | Parch==1')# Saving to excel, index=False i.e. do not write Index.
passengers_not_alone.to_excel('travelling_with_parent_sibling.xlsx', index=False)

10.链接多个操作

在结束之前,让我们了解一下熊猫的强大功能之一,即链接。您可以在数据帧上应用各种操作,而无需将其保存到临时数据帧(#NamesAreHard)中,这使得您的代码清晰易读。你可能已经注意到了,我在博客的其他部分也使用了这个—

# Here we first queried the data and then selected top 5 rows.
titanic_data.query('Sex=="male" and Survived==1').head(5)

上述代码在您不确定输出的情况下非常有用。它帮助您应用操作并直接检查最上面的行。

在上一节中,我们必须首先创建一个临时数据帧(males_survived ),用于存储幸存雄性的数据,然后使用它保存到一个 CSV 文件。使用链接,我们只用一行就可以做到,甚至不需要复制

# we used chaining to first filter and then save the records
titanic_data.query('Sex=="male" and Survived==1').to_csv('males_survived.csv', index=False)

在 Pandas 中,只要最后一个操作的结果是一个系列或一个数据帧,你几乎可以链接任何操作。

结论

我希望这篇文章能帮助你开始使用 Pandas,并简化你的数据分析过程。如前所述,在本文中,我试图涵盖数据分析过程不同领域的基本功能。我将继续为此添加更多内容。

Pandas 提供了许多不同的 API,可以帮助对数据执行高级操作,如绘图、样式化等。这些将在本系列的第 2 部分中讨论。做检查出"收起新手数据分析师状态(Part-2)

如果你在使用熊猫或数据分析时遇到任何问题,请在评论中告诉我,或在 LinkedIn 上 ping 我。我们可以试着一起解决。目前就这些了,下篇文章再见。

干杯!!!注意安全!!!继续学习!!!

熊猫:收起新手数据分析师的身份(第 2 部分)

原文:https://towardsdatascience.com/pandas-put-away-novice-data-analyst-status-part-2-8df616d5ac7c?source=collection_archive---------22-----------------------

了解如何使用新冠肺炎数据绘制、设计、多索引或透视您的熊猫数据框架。

各大洲报告的新病例数:作者

这是我正在做的熊猫系列的第二篇文章。如果你是熊猫新手,一定要先看看第一部分。

[## 熊猫:收起新手数据分析师的身份

熊猫如何让你成为更好的数据分析师?了解数据分析过程中不同步骤的一行程序。

towardsdatascience.com](/pandas-put-away-novice-data-analyst-status-part-1-7e1f0107dae0)

我称之为PutAwayNoviceDATAAanalystStatus,是一个强大的数据分析和操作库。在第 1 部分中,我们讨论了基本的 Pandas API 在数据分析过程中经历的不同步骤,比如读取数据、过滤、保存等等。在这里,我将重点介绍先进的熊猫 API,它们有助于轻松解决困难的分析问题。为了保持它的吸引力,我将把它作为一个问题解决练习,即首先我们将描述问题,然后我们将使用熊猫 API 用 1 或 2 行代码来解决它。

我将在 Data 中使用我们的世界提供的开源新冠肺炎数据。请注意,我们仅将此数据用于知识共享,数据中可能存在差异。

📚资源: Google Colab 实现 | Github 仓库 | 数据集📚

在这篇文章中,我们将举例说明—

  1. 使用 groupby()和 agg()进行数据聚合。
  2. 使用 plot()绘制数据。
  3. 熊猫数据帧样式使用。样式属性。
  4. 旋转数据-将长格式数据转换为宽格式。
  5. 使用 idxmin()和 idxmax()查找具有最小值或最大值的行和列。
  6. 多索引-简化您的查询。
  7. 将多个索引合并成一个索引。

在应用操作之前,让我们详细检查一下数据集。

数据集详细信息

我们的数据世界维护着每天更新的新冠肺炎数据。它包括确诊病例、死亡人数以及与新冠肺炎相关的检测。我们将使用 2020 年 8 月 7 日的数据,它包含 35 列,包含各种信息,如国家 GDP、洗手设施等。

出于演示目的,我将选择包含以下内容的数据子集—

  • iso_code —国家的 alpha 3 代码。
  • 大陆——世界各大洲。
  • 位置—国家。
  • 日期—报告案例的日期。
  • new _ cases 当天报告的新病例。
  • new _ deaths 当天报告的新死亡人数。
  • new_tests —在该日期进行的新电晕测试。

此外,我们将仅使用最近 10 天的数据,即从 2020 年 7 月 29 日到 8 月 7 日。如果你想知道如何过滤这些数据,请查看 Github 。

使用的新冠肺炎数据片段:作者

我相信你会看到许多与新冠肺炎有关的数据分析。让我们开始看看你如何自己做一个。

1.使用 groupby()和 agg()进行数据聚合

熊猫提供不同的 API 来聚合数据。让我们看看如何使用它们在一行中执行简单到复杂的聚合。

简单聚集

假设,我们需要找到每天报告的新病例总数。我们可以用——

# here we are chaining multiple operations together# Step 1: grouping data by date.
# Step 2: selecting new_cases from the group.
# Step 3: calculating the sum of the new_cases.
# Step 4: doing a groupby changes the index, so resetting it
# Step 5: selecting Last 5 records.data.groupby('date').new_cases.sum().reset_index().tail(5)

每天报告的新冠肺炎病例总数:作者

聚合多个字段

在上面的示例中,我们只聚合了一个字段,即“new_cases”。如果我们需要一个组有多个聚合怎么办?在这种情况下,我们可以将 groupby()和 agg()结合起来。比方说,我们需要找到—

  • 每天报告的病例总数。
  • 一个国家每天报告的最大病例数。
  • 每天报告的死亡总数。
  • 一个国家报告的最大死亡人数。
  • 每天进行的测试总数
  • 一天中报告数据的国家总数。

所有这些都可以用一行代码来完成—

# we are finding totals using sum and maximum using max
# Also, we used nunique to find unique number of countries reportingdata.groupby('date').agg({'new_cases':['sum','max'], 'new_deaths':['sum','max'],'new_tests':['sum'],'location':'nunique',}).reset_index().tail(5)

这给了我们一个很好的输出—

使用日期对新冠肺炎数据进行多重聚合:作者

使用这种聚合,我们得到了一个多列索引,在博客的后面,我们将看到如何将它组合成一个单一的索引。

命名聚合

如果您注意到上面的输出,它确实得到了结果,但是列的名称并不友好,因为它只是使用现有的列名。我们可以使用名为 aggregation 的熊猫来命名输出中的每个聚合。对于上面同样的问题,我们可以做—

# naming the aggregations, you can use any name for the aggregate
filtered_data.groupby('date').agg(total_new_cases = ('new_cases','sum'),max_new_cases_country = ('new_cases','max'),total_new_deaths = ('new_deaths','sum'),max_new_deaths_country = ('new_deaths','max'),total_new_tests = ('new_tests','sum'),total_countries_reported = ('location','nunique')).reset_index().tail(5)

使用 agg()的命名聚合:作者

2.使用 Plot()绘制数据

数据分析师的主要工作是将数据可视化。Pandas 中的每个数据帧都有一个 plot() API 用于绘图。默认情况下,Pandas 使用 Matlplotlib 作为绘图的后端。您可以使用各种其他后端。在这里,我将使用 Plotly 库,并将其配置为熊猫绘图后端。如果您没有安装 Plotly,那么您可以使用—

# if using anaconda distribution (recommended)
conda install -c conda-forge plotly# if using pip
pip install plotly

如果您已经安装了 Plotly,请确保您的版本≥ 4.8,因为它是运行以下代码部分所必需的。我们可以改变熊猫绘图后端使用—

# Set plotting backend as plotly
pd.options.plotting.backend = "plotly"

我们完成了配置。让我们通过几个例子来看看在熊猫中绘图是多么容易。

每个国家每天报告的新病例。

假设我们需要绘制每个国家每天报告的新病例。我们可以使用—

# generating a bar plot
data.plot.bar(x='date',y='new_cases', color='location')

上面的命令会生成一个漂亮的交互图(我确实改变了一些风格,请参考 Github) —

新冠肺炎每日按国家分类的新病例:作者

基于过去 10 天新增病例数的前 10 个国家

要获得排名靠前的国家,我们首先需要按“位置”对数据进行分组,然后用以下方式绘制

# Step 1: generating a new dataset based on each location i.e. country
# Step 2: doing the sum on new_cases followed by sorting
# Step 3: Selecting top 10 countries from the datasetdata.groupby(['location']).new_cases.sum().sort_values(ascending=False).head(10).plot.bar()

来源:作者图片

同样,您可以为不同的字段或数据的不同部分生成图。很简单,不是吗?

3.使用样式 API 的数据样式

很多时候我们需要在 Excel 和 Pandas 之间切换来做不同的事情,比如格式化数据或添加一些样式。Pandas 引入了样式 API,可以用来在 Pandas 中设置数据集的样式。我们可以使用样式进行各种操作。让我们看几个例子——

将数字转换为逗号分隔。

在我们的数据集中,new_cases、new_deaths 和 new_tests 存储为不适合表示的浮点值。使用样式,我们可以把它们改成逗号分隔的值,比如—

# formatting the data to show numbers as comma separateddata.style.format({'new_cases':'{0:,.0f}','new_deaths':'{0:,.0f}','new_tests':'{0:,.0f}',}).hide_index()

可展示格式的数字:作者

我们可以用它来做其他有趣的事情,比如为金额字段添加货币符号,改变小数点位数等。

突出显示最大值。

很多时候,我们需要突出显示列中的最大值。这可以通过使用—

# This will highlight the maximum for numeric column
data.style.highlight_max().hide_index()

每列突出显示的最大值:作者

基于数值大小的颜色映射。

有时,查看基于数值大小的颜色图是很有用的,即大值用深色显示,小值用浅色显示。熊猫造型提供了一个很好的 API,它用一行代码无缝地做到了这一点

# Adding blue color map for each numeric field
data.style.hide_index().background_gradient(cmap='Blues')

数值字段上的色彩映射表:作者

您可以使用样式 API 做各种其他事情。如果你想了解更多,请查阅熊猫文献。

4.透视-将数据从长格式转换为宽格式

如果您熟悉 Excel,您应该听说过数据透视表。Pandas pivot 帮助我们将长数据(即以行存储的数据)转换为宽数据(即以列存储的数据)。熊猫为旋转提供了两种不同的 APIs

  • 在枢轴上转动
  • 数据透视表

我们将使用几个例子来检查每一个。

透视( )

考虑这样一个问题,我们需要为前 10 个国家查找新冠肺炎随时间变化的新案例。

首先,我们需要找到每天排名前 10 位的国家,我们可以使用下面的代码来完成—

# Step 1: create a group based on date and location
# Step 2: order it by number of new cases.grouped_data = data.groupby(['date','location']).new_cases.sum().sort_values(ascending=False)# we have data for each date grouped by location.
grouped_data.head(5)Output:
date        location     
2020-07-30  United States    74985.0Brazil           69074.0
2020-07-31  United States    68032.0
2020-08-01  United States    67023.0
2020-08-07  India            62538.0# Next we need to select top 10 countries for each date
# Step 3: create a new group based on date. 
# Step 4: select top 10 records from each group.top10_countries = grouped_data.groupby('date').head(10).reset_index()

现在,我们有每天的前 10 个国家,但这是以长格式存储的,即每天我们有多行。我们可以使用 pivot 将这些数据转换成宽格式,使用—

# Step 5: pivoting data on date and location
top10_countries_pivot = top10_countries.pivot(index='date', columns='location', values='new_cases')

在上面的命令中,我们说对于每个日期,用 new_cases 的值为每个位置创建新列。这将导致—

使用 Pivot 转换的新冠肺炎数据剪报:作者

接下来,我们可以直接使用 Seaborn 为透视数据生成一个漂亮的热图。

# Step 6: plotting heatmap using Seaborn
sns.heatmap(top10_countries_pivot, annot=True, fmt='.0f')

数据透视表( )

在上面的例子中,我们只有一行(日期,地点)的组合,即 2020-08-07,我们只有一行“印度”。如果我们需要找到每个洲的新病例数,该怎么办?在这种情况下,在给定的日期,每个洲有多个行,即行数等于该洲的国家数。为了解决这个问题,Pandas 提供了 pivot_table() API,它可以聚合记录,将其转换为一行。让我们看看它是如何实现的—

# Creating a pivot table for continent# We do not need to select top 10 records here as we have only 6 continents
# Notice the aggfunc below, it will actually sum the new_cases for each country in the continent.continent_pivot = filtered_data.pivot_table(index='date',columns='continent', values='new_cases', aggfunc='sum')

各大洲的新冠肺炎病例:作者

各大洲的新冠肺炎热图:作者

5.使用 idxmin(),idxmax()

您如何在数据透视表中找到具有最小或最大事例的国家/地区?我们可以使用 idxmin()或 idxmax()来实现。Idxmin()给出给定轴(即行或列)的最小值的索引,Idxmax()给出最大值的索引。

# find country with maximum cases 
# axis=1 to find max in the row, default is columntop10_countries_pivot.idxmax(axis=1)Output:
date
2020-07-29    United States
2020-07-30    United States
2020-07-31    United States
2020-08-01    United States
2020-08-02    United States
2020-08-03            India
2020-08-04            India
2020-08-05    United States
2020-08-06           Brazil
2020-08-07            India# find country with minimum cases
# axis=1 to find max in the row, default is columntop10_countries_pivot.idxmin(axis=1)# This is among the top 10 countries
Output:
date
2020-07-29      Bangladesh
2020-07-30      Bangladesh
2020-07-31     Philippines
2020-08-01     Philippines
2020-08-02     Philippines
2020-08-03     Philippines
2020-08-04            Peru
2020-08-05    South Africa
2020-08-06           Spain
2020-08-07           Spain

6.使用 set_index()的多索引

Pandas 支持行和列的多重索引。这对于回答简单的问题很方便。例如,如果我们需要找到数据

  • 在一个特定的大陆的特定的一天。
  • 在特定的日子特定的地点。
  • 某些日子的一些地点。

有很多方法可以做到这一点,但是让我们看看使用多索引有多简单。首先,使用 set_index API 创建多索引。

# Creating Index on continent, location and date
# The index will be created in the order suppliedindexed_data = data.set_index(['continent','location','date']).sort_index()# values of the index
indexed_data.index.valuesOutput:
array([('Africa', 'Algeria', '2020-07-29'),('Africa', 'Algeria', '2020-07-30'),('Africa', 'Algeria', '2020-07-31'), ...,('South America', 'Venezuela', '2020-08-05'),('South America', 'Venezuela', '2020-08-06'),('South America', 'Venezuela', '2020-08-07')], dtype=object)

现在,我们对每一行都有多索引,也就是说,要查询第一行,我们需要-

indexed_data.loc[(‘Africa’,’Algeria’,’2020–07–29')]

熊猫的多指标数据:作者

让我们看几个例子,看看创建多索引有什么帮助。

2020 年 8 月 7 日北美(大陆)美国(所在地)报告的新增病例数。

indexed_data.loc[('North America','United States','2020-08-07'),'new_cases']Output:
59755.0

2020 年 8 月 7 日亚洲报告的新病例

在这里,我们希望获得亚洲所有国家的数据。我们可以通过在 location 中传递 slice(None)来实现,这意味着获取所有位置。

indexed_data.loc[('Asia',slice(None),'2020-08-07'),'new_cases']Output(a snippet):
continent  location              date      
Asia       Afghanistan           2020-08-07       41.0Armenia               2020-08-07      233.0Azerbaijan            2020-08-07      144.0Bahrain               2020-08-07      375.0Bangladesh            2020-08-07     2977.0Bhutan                2020-08-07        3.0Brunei                2020-08-07        0.0Cambodia              2020-08-07        0.0China                 2020-08-07      132.0Georgia               2020-08-07        0.0India                 2020-08-07    62538.0

8 月 6 日和 7 日印度和美国报告了新病例

我们可以传递任何索引的值列表。在本例中,我们没有提供洲,也没有为位置和日期选择多个值。

indexed_data.loc[(slice(None),[‘India’,’United States’],[‘2020–08–06’,’2020–08–07']),’new_cases’]Output:
continent      location       date      
Asia           India          2020-08-06    56282.02020-08-07    62538.0
North America  United States  2020-08-06    52804.02020-08-07    59755.0
Name: new_cases, dtype: float64

你可以用多索引做很多事情。如果你想了解更多,请参考拜伦·多伦写的一篇好文章’如何在熊猫中使用多指数来提升你的分析。

7.将多个索引合并成一个索引。

很多时候,当我们进行聚合时,我们会得到多列索引,比如—

# multiple aggregations on new_cases
grouped_data = data.groupby('date').agg({'new_cases':['sum','max','min']})

多列索引:作者

这使得得到实际结果有点困难。我们可以通过下面的方法将这些转换成一列—

# columns in grouped data
grouped_data.columnsOutput:
MultiIndex([('new_cases', 'sum'),('new_cases', 'max'),('new_cases', 'min')],)

使用简单的代码组合上面的列,如 new_cases_sum、new_cases_max、new_cases_min

# here are we just joining the tuple with '_'
# this works for level-2 column indexes onlynew_columns = ['%s%s' % (a, '_%s' % b if b else '') for a, b in grouped_data.columns]
new_columnsOutput:
['new_cases_sum', 'new_cases_max', 'new_cases_min']# change grouped_data columns.
grouped_data.columns = new_columns

多列索引转换为单个索引:作者

结论

我希望这篇文章能帮助你提高数据分析技能,节省分析大型数据集的时间。我知道阅读时很少有事情看起来很复杂,所以我建议你下载这个笔记本来玩。如果你面临任何问题,请在评论中告诉我,并随时在 LinkedIn 上联系我。仍然有许多不错的熊猫 API 我不能浏览,也许我会写一个第 3 部分来涵盖这些。目前,这就是全部。

干杯!!!注意安全!!!继续学习!!!

熊猫查询类似 SQL 的查询

原文:https://towardsdatascience.com/pandas-query-for-sql-like-querying-279dc8cbfe3f?source=collection_archive---------18-----------------------

使用 pandas 查询函数查询数据帧的数据科学家 python 教程

由un splash【1】上的 Mélody P 拍摄

目录

  1. 资料组
  2. 熊猫
  3. 询问
  4. 教程代码
  5. 摘要
  6. 参考

资料组

本分析和 pandas 查询教程中使用的数据集是一个虚拟数据集,创建该数据集是为了模拟具有文本和数字特征的数据帧。请随意使用您自己的。csv 文件,包含文本和/或数字列,以遵循教程。

熊猫

Pandas【2】是数据科学家和机器学习工程师最常用的库之一。它主要用于构建模型的探索性数据分析步骤,以及模型结果的即席分析。它还包含几个功能,包括查询功能。

询问

pandas 中的查询函数是一个有用的函数,它的作用类似于 SQL 中的*‘where’*子句。然而,它的好处是,你不需要不断地从 pandas、Jupyter Notebook 和你目前使用的 SQL 平台切换。下面列出了其他一些好处:

  • 编译几个条件
  • 一个简单的函数,可以处理你的熊猫数据帧
  • 引用描述性统计数据,而不是必须进行子查询

教程代码

我已经编写了几个如何使用 pandas 查询功能的例子。下面的屏幕截图总结了一些有用的查询示例。下面,您可以看到如何同时满足文本和数字条件。查找特定列包含特定文本值的行,或者使用 '@' 符号创建描述性统计。例如, '@mean_of_column' 引用了您使用*建立的值。函数均值()'。在第 65 行,返回的行具有一个‘蓝色’值和一个‘已确认 _ 恢复’值,该值大于‘已确认 _ 恢复’本身的平均值,同时还包括‘标签 _ 3’*值。

返回相等的行以及其他几个条件的示例。作者截图[3]。

灰色框中引用的教程代码是用于演示查询函数的所有代码。首先,我进口了熊猫并读取了我的数据帧。然后,我添加新的行,我知道这些行将满足某些条件,以显示如何使用查询函数。*‘append’*函数在这里也很有用,因为它可以快速地向数据帧中添加新行,而不必显式地以序列格式调用每一列。我返回了 'df.tail()' ,以查看返回的行是否是我所期望的。

然后,我返回一列中的值等于另一列中的值的行。您也可以使用相同的逻辑,但是反过来看看您指定的列的哪些值不相等。接下来,您可以比较一列的值是否大于另一列的值,反之亦然。

我认为,query 最有用的特性是 '@' 方法。就像 SQL 中可以使用子查询来引用选择满足特定条件的行一样,这个方法也可以。 '@' 方法保存您想要比较的值。对于下面的例子,我查看了一列的平均值进行比较。

最后,通过输入类似于 SQL 中的' & ' ,可以使用查询函数在一行代码中执行多个条件。

# All the python code below for use:# import libraryimport pandas as pd # read in your dataframedf = pd.read_csv('/Users/example.csv')# write out new rowsrows = [pd.Series([100, 100, 20,'Blue','Label_1'], index=df.columns),pd.Series([100, 80, 60,'Blue','Label_1'], index=df.columns),pd.Series([80, 60, 100,'Blue','Label_1'], index=df.columns)]# append the multiple rowsnew_df = df.append(rows , ignore_index=True)# check the newest 3 rows you madenew_df.tail(3)# return rows where values from one column equal that of another# they do not for this comparisonnew_df.query('Confirmed_Test == Confirmed_New')# return rows where values from one column equal that of another# they do for this comparisonnew_df.query('Confirmed_Test == Confirmed_Recovery')# return rows where values from one column do not equal that of another# they do for this comparisonnew_df.query('Confirmed_New != Confirmed_Recovery').head()# return rows where values from one column are bigger than that of anothernew_df.query('Confirmed_New > Confirmed_Recovery').head()# see which rows where the 'Confirmed_New' values# are greater than the mean of the total column# use the '@' to reference 'cn_mean'cn_mean = new_df['Confirmed_New'].mean()new_df.query('Confirmed_New > @cn_mean').head()# multiple conditions examplecn_min = new_df['Confirmed_New'].min()cn_max = new_df['Confirmed_New'].max()new_df.query('Confirmed_New > @cn_min & Confirmed_New < @cn_max').head()# text conditions# use double quotes for matching on the string value# all the rows returned have 'Blue' for the 'Text_Feature' columnnew_df.query('Text_Feature == "Blue"').head()# return rows which have a 'Blue' value, and a 'Confirmed_Recovery' that is greater# than the mean of 'Confirmed_Recovery' itself, while also satisfying the 'Label_3' value# only 3 return here (did not print out head())cr_mean = new_df['Confirmed_Recovery'].mean()new_df.query('Text_Feature == "Blue" & Confirmed_Recovery > @cr_mean & Text_Predictor == "Label_3"')

要查看 python 格式的代码而不是写出的代码,下面是嵌入的要点【4】:

摘要

pandas 的查询功能是操作数据框架的一种简单快捷的方式。您可以使用类似 SQL 的子句返回满足您确定的条件的某些行。这是有益的,如果你已经在你的 Jupyter 笔记本。ipynb 文件或。py 文件,而不必在 SQL 平台上重新上传或执行 SQL 命令。熊猫查询也很直观,不需要很长时间就能学会。我希望本文中的例子对您有用。感谢您的阅读!

参考

1 梅洛迪 P , Unsplash (2017)

[2]熊猫,熊猫 (2020)

[3] M.Przybyla,截图(2020 年)

[4] M.Przybyla,要点 (2020)

Pandas 查询方法节省了对变量的双重处理

原文:https://towardsdatascience.com/pandas-query-method-saves-double-handling-of-variables-9293d703b804?source=collection_archive---------17-----------------------

最后更新时间:2020 年 1 月

使用。query()可以使我们在选择数据时不必在一行代码中多次键入数据帧的变量名。

在 pandas DataFrame 对象中检索具有特定条件的行的标准方法需要“双重处理”;不是特别优雅。

例如,我们想要检索列 A 大于 1 的行,这是使用的标准方法。loc 属性。

*## Setup ##**# Import pandas* **import** pandas **as** pd*# Create dataframe from dict* # Specify the type in the suffix of each column name
my_df = pd.DataFrame({**"A_int"**: [1, 2, -3],**"B_float"**: [7.5, 1.9, 8.4],**"C_str"**: [**'eight'**, **'nine'**, **'Ten'**],**"D_str"**: [**'Mar 2017'**, **'May 2018'**, **'Jun 2016'**]})*# Convert to datetime column* my_df[**'D_date'**] = pd.to_datetime(my_df[**'D_str'**])"""
>>> my_dfA_int  B_float  C_str     D_str     D_date
0      1      7.5  eight  Mar 2017 2017-03-01
1      2      1.9   nine  May 2018 2018-05-01
2     -3      8.4    Ten  Jun 2016 2016-06-01
"""## Show loc example 1 ##ex_1_loc = my_df.loc[my_df[**'A_int'**] > 0, :]"""
>>> ex_1_locA_int  B_float  C_str     D_str     D_date
0      1      7.5  eight  Mar 2017 2017-03-01
1      2      1.9   nine  May 2018 2018-05-01
"""

这里,我们获得了布尔行序列,其中对于给定的行,A 列大于 0。。loc 用于取出设置为 True 的行。注意,变量 my_df 在一行代码中使用了两次。
幸好这个变量名不是很长。我发现这种对变量的“双重处理”在语法上类似于 R 中的基本方法,特别是在嵌套和完全不必要的时候。

一些其他语言可以以更易读的格式执行这种过滤:

## SQL EXAMPLE ##
SELECT *
FROM my_df
WHERE A > 0## R-TIDYVERSE EXAMPLE ##
library(tidyverse)
my_df %>%dplyr::filter(A > 0)

对于 python,我们可以用 pandas 的“查询”方法更简单地做到这一点(类似于上面的 SQL / R-Tidyverse 结构)。查询只返回符合给定条件的行,所有列都保留在数据帧中。

#ex_1_loc = my_df.loc[my_df[**'A_int'**] > 0, :]
ex_1_query = my_df.query("A > 0")
# Or use @ when referencing a variable
pivot_val = 0
ex_1a_query = my_df.query("A > @pivot_val")

标准的熊猫方法经常会让我们看到双重图像 src:https://pix abay . com/photos/panda-family-pandas-cute-bamboo-3811734/

让我们再看六个例子,在这些例子中,query 是对的适当替代。锁定方法

2.对外部列表进行筛选

给定一个外部列表,获取数据帧中某一列与该列表中的一个元素匹配的行

*# Create a list of legitimate entries* legit_entries = [**'eight'**, **'nine'**, **'ten'**]*# Filter column 'C_str' by the array* ex_2_loc = my_df.loc[my_df[**'C_str'**].isin(legit_entries), :]
ex_2_query = my_df.query(**"C_str in @legit_entries"**)"""A_int  B_float  C_str     D_str     D_date
0      1      7.5  eight  Mar 2017 2017-03-01
1      2      1.9   nine  May 2018 2018-05-01
"""

3.列比较

比较两列—这需要在中进行三重处理。锁定示例。

*# Return rows where 'A_int' is greater than 'B_float'* ex_3_loc = my_df.loc[my_df[**'A_int'**] > my_df[**'B_float'**], :]
ex_3_query = my_df.query(**"A_int > B_float"**)"""A_int  B_float C_str     D_str     D_date
1      2      1.9  nine  May 2018 2018-05-01
"""

4.多条件过滤

在可能的多个列上使用多个条件进行筛选。 &| 位运算符都是允许的。

*# Return rows where 'A_int' is greater than zero
# And where C_str is in the legit_entries array* ex_4_loc = my_df.loc[(my_df[**"A_int"**] > 0) &(my_df[**'C_str'**].isin(legit_entries)), :]
ex_4_query = my_df.query(**"A_int > 0 & C_str in @legit_entries"**)"""A_int  B_float  C_str     D_str     D_date
0      1      7.5  eight  Mar 2017 2017-03-01
1      2      1.9   nine  May 2018 2018-05-01
"""

5.时间戳

查询识别日期,并可以将它们与字符串进行比较。查询引号内的所有字符串都必须用引号括起来。

*# Return rows where D_date is after Jan 2018* ex_5_loc = my_df.loc[my_df[**'D_date'**] > **'Jan 2018'**, :]
ex_5_query = my_df.query(**"D_date > 'Jan 2018'"**)"""A_int  B_float C_str     D_str     D_date
1      2      1.9  nine  May 2018 2018-05-01
"""

6.比较前的列转换

您可以在比较之前对给定的列执行函数。
注意 dataframe 的输出仍然包含原来格式的 C_str 列?

*# First convert C_str to lowercase, than compare entries* ex_6_loc = my_df.loc[my_df[**'C_str'**].str.lower().isin(legit_entries),:]
ex_6_query = my_df.query(**"C_str.str.lower() in @legit_entries"**)"""A_int  B_float  C_str     D_str     D_date
0      1      7.5  eight  Mar 2017 2017-03-01
1      2      1.9   nine  May 2018 2018-05-01
2     -3      8.4    Ten  Jun 2016 2016-06-01
"""

7。包含空格
的列名最初禁止使用 pandas 查询,这个问题在 0.25.2 中已经解决。
用反斜杠引用该列。列中的其他特殊字符可能不起作用。

*# Return rows where 'E rogue column str' column contains the word 'this'* my_df[**'E rogue_column_str'**] = [**'this'**, **'and'**, **'that'**]"""
>>>my_dfA_int  B_float  C_str     D_str     D_date E rogue_column_str
0      1      7.5  eight  Mar 2017 2017-03-01               this
1      2      1.9   nine  May 2018 2018-05-01                and
2     -3      8.4    Ten  Jun 2016 2016-06-01               that
"""ex_7_loc = my_df.loc[my_df[**"E rogue_column_str"**] == **'this'**, :]
ex_7_query = my_df.query(**"`E rogue_column_str` == 'this'"**))"""A_int  B_float  C_str     D_str     D_date E rogue_column_str
0      1      7.5  eight  Mar 2017 2017-03-01               this
"""

克服“项目”贬值

在熊猫的最新版本(在撰写本文时为 0.25.3)中,。item() 方法已被弃用。结合查询功能, item 是一个非常有用的工具,可以在假设只返回一行的情况下从给定的列中获取单个值。这将把列从类型 pd 转换成。系列的数据类型,如 int、str、float 等。如果返回多行,方法将引发 ValueError。

我们可以使用 squeeze 方法作为替代方法,只需对代码做一些小的修改。与 item 类似,当筛选后的系列只有一行长时,squeeze 会将 pandas 系列从系列类型转换为数据类型。但是,如果序列中存在多个值,则不会引发 value error而只是返回同一个序列。我们可以通过检查返回值是否仍然是 series 类型来利用这一点。

*# Previous code* **try**:single_value = ex_3_query[**'B_float'**].item()print(single_value)
**except** ValueError:print(**"Error, expected to return only one value, got %d"** %len(ex_3_query[**'B_float'**]))*# New code* single_value = ex_3_query[**'B_float'**].squeeze()
**if** isinstance(single_value, pd.Series):print(**"Error, expected to return only one value, got %d"** %len(ex_3_query[**'B_float'**]))
**else**:print(single_value)

引用:
熊猫查询 API

熊猫重采样()处理时间序列数据时你应该知道的技巧

原文:https://towardsdatascience.com/pandas-resample-tricks-you-should-know-for-manipulating-time-series-data-7e9643a7e7f3?source=collection_archive---------0-----------------------

你应该知道的一些最有用的熊猫把戏

照片由维里·伊万诺娃在 Unsplash 上拍摄

时间序列数据在数据科学项目中很常见。通常,您可能有兴趣将时间序列数据重采样到您想要分析数据或从数据中获得更多见解的频率1

在本文中,我们将介绍一些使用 Pandas resample()函数对时间序列数据进行重采样的例子。我们将讨论以下常见问题,并帮助您开始时间序列数据操作。

  1. 下采样和执行聚合
  2. 使用自定义基数缩减取样
  3. 向上采样和填充值
  4. 实际例子

源代码请查看笔记本。

1.下采样和执行聚合

下采样是将时间序列数据集重新采样到更宽的时间范围。比如从几分钟到几小时,从几天到几年。结果的行数将会减少,值可以用mean()min()max()sum()等进行聚合。

让我们借助一个例子来看看它是如何工作的。

假设我们有一个关于销售的数据集。

df_sales = pd.read_csv('sales_data.csv', **parse_dates=['date'],** **index_col=['date']**
)

df_sales的例子

要获得每 2 小时增加的销售总数,我们可以简单地使用resample()将数据帧下采样到 2 小时的区间中,并对落入区间中的时间戳值求和。

df_sales.**resample('2H')**.**sum()**

resample('2H').sum()的输出

为了执行多重聚合,我们可以将聚合函数列表传递给agg()方法。

df_sales.resample('2H').**agg(['min','max', 'sum'])**

多个聚合的输出

2.自定义缩减采样base

默认情况下,对于平均细分为 1 天/月/年的频率,聚合间隔的“原点”默认为0。因此,对于2H频率,结果范围将为00:00:0002:00:0004:00:00、…、22:00:00

对于我们正在使用的销售数据,第一条记录有一个日期值**2017–01–02 09:02:03** ,因此让输出范围从09:00:00开始比从08:00:00开始更有意义。为此,我们可以使用参数base将聚合间隔的“原点”设置为不同的值,例如,设置base=1,这样结果范围就可以从09:00:00开始。

df_sales.resample('2H', **base=1**).sum()

带参数base=1

3.向上采样和填充值

上采样是与下采样相反的操作。它将时间序列数据集重新采样到一个更小的时间范围。比如从几小时到几分钟,从几年到几天。结果将增加行数,额外的行值默认为NaN。常用内置方法ffill()bfill()进行正向填充或反向填充来代替NaN

让我们做一个数据框架来演示。

df = pd.DataFrame({ 'value': [1, 2, 3] }, **index=pd.period_range('2012-01-01',freq='A',periods=3)**
)

按季度对一年进行重新采样并向前填充数值。正向填充方法ffill()将使用最后一个已知值替换NaN

df.resample(**'Q'**).**ffill()**

df.resample('Q').ffill()

按季度对一年进行重新采样,并反向填充数值。反向填充方法bfill()将使用下一个已知值替换NaN

df.resample(**'Q'**).**bfill()**

df.resample('Q').bfill()

4.实际例子

让我们来看看如何使用熊猫resample()来处理一个现实世界的问题。

假设我们有 2 个数据集,一个是月销售额df_sales,另一个是价格df_pricedf_price只有价格变化的记录。

我们想计算每个月的 总销售额 ,预期产量如下。

计算中的难点在于,我们需要检索每个月的价格,并将其组合回数据中,以便计算总价。

一个巧妙的解决方案是使用熊猫resample()功能。一行代码可以检索每个月的价格。

步骤 1:按月对价格数据集进行重新采样,并向前填充值

df_price = df_price.**resample('M')**.**ffill()**

通过调用resample('M')按月对给定的时间序列进行重新采样。之后,调用ffill()向前填充值。你是不是有点困惑?详情请看下图。

第二步:合并结果并计算总销售额

df = **pd.concat([df_sales, df_price], axis = 1)****df['total_sales'] = df['num_sold'] * df['price']**

带参数axis=1的熊猫concat()函数用于横向组合df_salesdf_price。之后,可以使用逐元素乘法df['num_sold'] * df['price']计算总销售额。

通过执行上面的语句,您应该得到如下所示的输出:

最终输出

结论

Pandas resample()函数是一个简单、强大且高效的功能,用于在频率转换期间执行重采样操作。

我希望这篇文章能帮助你节省分析时间序列数据的时间。我建议你查看一下关于resample() API 的文档,并了解你可以做的其他事情。

感谢阅读。请查看笔记本获取源代码,如果您对机器学习的实用方面感兴趣,请继续关注。

你可能会对我的其他一些熊猫文章感兴趣:

  • 如何对熊猫数据帧进行自定义排序
  • 何时使用 Pandas transform()函数
  • 你应该知道的熊猫串联()招数
  • Pandas 中 apply()和 transform()的区别
  • 使用熊猫方法链接提高代码可读性
  • 在 Pandas 数据帧中处理日期时间
  • 熊猫阅读 _csv()你应该知道的招数
  • 你应该知道的用熊猫 read_csv() 解析日期列的 4 个技巧

更多教程可以在我的 Github 上找到

参考

  • 1 如何使用 Python 对时间序列数据进行重采样和插值

熊猫——用这些简单的技巧节省记忆

原文:https://towardsdatascience.com/pandas-save-memory-with-these-simple-tricks-943841f8c32?source=collection_archive---------14-----------------------

如何在内存使用方面更高效地使用熊猫

张家瑜在 Unsplash 上拍照

处理小型数据时,内存不是一个大问题。然而,当涉及到大型数据集时,有效地使用内存就变得势在必行。我将介绍一些非常简单的技巧来减小熊猫数据帧的大小。我将使用 Kaggle 上关于加密货币市场价格的相对较大的数据集。让我们从将数据读入熊猫数据帧开始。

import pandas as pd
import numpy as npdf = pd.read_csv("crypto-markets.csv")
df.shape
(942297, 13)

数据帧有将近一百万行和 13 列。它包括加密货币的历史价格。

让我们检查一下这个数据帧的大小:

df.memory_usage()
Index               80
slug           7538376
symbol         7538376
name           7538376
date           7538376
ranknow        7538376
open           7538376
high           7538376
low            7538376
close          7538376
volume         7538376
market         7538376
close_ratio    7538376
spread         7538376
dtype: int64

memory_usage()返回每行使用多少内存(以字节为单位)。我们可以通过几个数学运算来检查完整数据帧的内存使用情况,单位为兆字节:

df.memory_usage().sum() / (1024**2) #converting to megabytes
93.45909881591797

所以总大小是 93.46 MB。

让我们检查一下数据类型,因为在某些情况下,我们可以用更易于存储的数据类型来表示相同数量的信息。

df.dtypes
slug            object
symbol          object
name            object
date            object
ranknow          int64
open           float64
high           float64
low            float64
close          float64
volume         float64
market         float64
close_ratio    float64
spread         float64
dtype: object

首先想到的应该是“对象”数据类型。如果我们有分类数据,最好使用“类别”数据类型而不是“对象”,尤其是当类别的数量与行数相比非常低的时候。“slug”、“symbol”和“name”列就是这种情况:

df.slug.value_counts().size
2071

有 2072 个类别,相对于 100 万行是非常低的。让我们将这些列转换为“category”数据类型,并查看内存使用的减少情况:

df[['slug','symbol','name']] = df[['slug','symbol', 'name']].astype('category')df[['slug','symbol','name']].memory_usage()
Index          80
slug      1983082 #previous: 7538376
symbol    1982554
name      1983082
dtype: int64

因此每列的内存使用减少了%74。让我们看看我们总共存了多少钱:

df.memory_usage().sum() / (1024**2) #converting to megabytes
77.56477165222168

总大小从 93.46 MB 减少到 77.56 MB。

“ranknow”列显示不同货币类别之间的排名。既然有 2072 个类别,那么最大值应该是 2072。

df.ranknow.max()
2072

“ranknow”列的数据类型是 int64,但是我们也可以使用 int16 表示从 1 到 2072 的范围。int16 可以表示的范围是-32768 到+32767。

df["ranknow"] = df["ranknow"].astype("int16")df["ranknow"].memory_usage()
1884674 #previous: 7538376

因为我们从 int64 降低到 int16,所以内存使用如预期的那样减少了%75。

数据集中的浮点数用“float64”表示,但我可以用“float32”表示这些数字,这样我们就可以有 6 位数的精度。我认为 6 位数就足够了,除非你是在做高灵敏度的测量。

  • float32(等效 C 类型:float): 6 位精度
  • float64(等效 C 类型:double): 15 位精度
floats = df.select_dtypes(include=['float64']).columns.tolist()df[floats] = df[floats].astype('float32')df[floats].memory_usage()
Index               80
open           3769188 #previous: 7538376
high           3769188
low            3769188
close          3769188
volume         3769188
market         3769188
close_ratio    3769188
spread         3769188
dtype: int64

从“float64”到“float32”的转换如预期的那样将这些列的内存使用量减少了%50。

float32 有 6 位精度

在某些情况下,数据帧可能有冗余列。让我们看一下现有的数据框架:

“slug”、“symbol”、“name”等栏目以不同的格式表示同一事物。这三列中只有一列就足够了,所以我可以删除两列。您拥有的数据帧可能没有这样的列,但寻找冗余或不必要的列总是一个好的做法。例如,数据帧可能包括“计数”、“值”和“总和”列。我们可以很容易地获得总数乘以计数和值,所以总和列是不必要的。有些列可能与你想完成的任务完全无关,所以只需寻找这些列。在我的例子中,我将删除“符号”和“名称”列,并使用“slug”列:

df.drop(['symbol','name'], axis=1, inplace=True)

让我们检查最终数据帧的大小:

df.memory_usage().sum() / (1024*1024)
39.63435745239258

总大小从 93.46 MB 减少到 36.63 MB,我认为这是一个伟大的成就。我们能够节省 56,83 MB 的内存。

减小尺寸的另一个优点是简化计算。使用 float32 进行计算比使用 float64 花费的时间少。

我们应该尽可能地寻找减小尺寸的方法。

感谢您的阅读。如果您有任何反馈,请告诉我。

熊猫系列&数据框讲解

原文:https://towardsdatascience.com/pandas-series-dataframe-explained-a178f9748d46?source=collection_archive---------19-----------------------

理解 Pandas 系列和 DataFrame 数据结构的综合指南

照片由埃莉诺拉·阿尔巴希在 Unsplash 上拍摄

介绍

作为一名成功的数据科学家,需要不断学习和提高我们使用各种工具的技能。如今,与数据科学同义的一个工具是熊猫。Pandas 是一个非常强大的开源库,用 Python 编写。它提供了一套多样化的工具,我们作为数据科学家可以用来清理、操作和分析数据。今天我们从基础开始,学习熊猫中最常见的两种数据结构系列和数据框架。

入门指南

安装熊猫& Numpy

Pandas 和 Numpy 是用 Python 编写的开源库,你可以在你的 Python 脚本中使用它们。有几种方法可以安装这些软件包。默认情况下,如果您使用的是 Anaconda ,这些包已经安装好了。如果您没有使用 Anaconda,那么最简单的安装选项是使用pip,这是 Python 推荐的安装包。您可以在 PyPA 的文档中找到pip的详细安装说明。

一旦pip完成安装,您可以在终端上运行以下命令来安装 Pandas 和 Numpy pip install pandas pip install numpy。安装后,您可以使用下面的语法将 Pandas 和 Numpy 库导入到您的脚本中。

上面的 Python 片段显示了导入 Pandas 和 Numpy 包的语法。

熊猫系列

Pandas 系列数据结构是一个一维标签数组。它是数据帧的主要构造块,构成数据帧的行和列。您可以查看以下系列的构造函数。

上面的 Python 片段显示了熊猫系列的构造函数。

data参数可以接受几种不同的数据类型,如n 数组、字典和标量值。index参数接受类似数组的对象,这将允许您标记索引轴。如果您没有向index参数传递一个条目,而向data参数传递一个字典,那么 Pandas 将使用字典键作为索引标签。您可以通过设置dtype参数来设置系列的数据类型。如果一个数据类型没有被指定,那么 Pandas 将会对数据类型进行推断。name参数如其所暗示的那样,允许您命名您已经创建的系列。

使用字典创建系列

下面我们提供了一个示例 Python 片段,您可以使用它来创建一个系列。

上面的 Python 片段演示了如何使用字典创建和命名一个系列。

上图显示了执行 Python 代码片段创建系列的结果。

从上面的控制台输出中,我们可以看到该系列使用了字典键作为索引,该系列被命名为series_from_dict,Pandas 推断出一个数据类型为float64

从 ndarray 创建系列

生成测试序列的最快方法之一是使用 NumPy 的random.randint(),它产生一个填充了随机整数的 ndarray。

上面的 Python 片段演示了如何使用 ndarray 创建和命名一个系列。

上图显示了执行 Python 代码片段的结果。

从标量值创建序列

我们今天要看的最后一个方法是使用标量值创建一个序列。在这里,您可以为data分配一个值,并在索引长度内重复该值。

上面的 Python 片段展示了如何通过传递标量值来创建序列。

上图显示了执行 Python 代码片段的结果。

熊猫数据框

Pandas DataFrame 是由列和行组成的二维数据结构。您可以将 DataFrame 视为类似于 CSV 或关系数据库表。下面你可以看到创建数据帧的构造函数。

上面的 Python 片段显示了熊猫数据帧的构造函数。

与 Series 类似的data参数可以接受广泛的数据类型,例如 Series、Series 字典、结构化数组和 NumPy 数组。除了能够将索引标签传递给index,DataFrame 构造函数还可以通过columns接受列名。

为系列词典创建数据框架

生成数据帧最简单的方法之一是创建一个包含 Series 的字典。字典键将成为数据帧的列标签,而系列索引将成为数据帧的行标签。下面是一个 Python 片段,您可以用它来生成您的第一个数据帧。

上面的 Python 片段展示了如何使用系列字典创建 DataFrame。

上图显示了执行 Python 脚本的结果。

上面的控制台输出清楚地展示了 DataFrame 数据结构。字典关键字column_acolumn_bcolumn_c现在形成了带标签的列,序列索引abcde是数据帧行标签。

为列表字典创建数据框架

Pandas DataFrame 构造函数也可以接收一个列表字典。下面我们为您提供了一个 Python 片段,您可以使用它来实现这一点。这里,我们通过 DataFrame 构造函数中的index参数分配了行标签。

上面的 Python 片段展示了如何从列表字典创建 DataFrame。

上图显示了从列表字典创建 DataFrame 的结果。

接下来去哪里?

既然您已经介绍了 Pandas 的基本构件,您的下一步应该是学习如何通过迭代数据帧或使用 Pandas Profiling 进行分析来导航数据帧。

再次感谢您花时间阅读我们的故事,我们希望您发现它有价值!

熊猫侧桌刚刚宣布

原文:https://towardsdatascience.com/pandas-sidetable-just-announced-708e5f65938f?source=collection_archive---------14-----------------------

对数据框架的信息丰富、见解深刻的概述。

照片由马库斯·斯皮斯克在 Unsplash 拍摄

Pandas 是一个非常强大和通用的 Python 数据分析库,它加速了数据科学项目的预处理步骤。它提供了许多在数据分析中非常有用的函数和方法。

虽然熊猫的内置功能能够执行有效的数据分析,但定制的功能或库为熊猫增加了价值。在本帖中,我们将探究其中一个附加组件。

昨天,克里斯·莫菲特宣布了一个新的名为 sidetable 的熊猫实用程序库。这里是 sidetable 的 github repo 。我发现它非常有用,并计划在我的日常分析中应用。这就是为什么我想通过一些例子来分享和传播这个词。

Sidetable 基于选定的列创建频率表。假设我们有一个数据集,其中包含某个分类变量的一些测量值(例如模型)。我们有许多不同的模型,每个模型都有许多观察值(行)。通过使用 sidetable,我们可以得到一个概览,显示每个模型在数据集中所占的份额。这也可以使用 pandas 的**value_counts**功能来实现,但是 sidetable 提供的信息更多,我们将在示例中看到。

如果你使用 jupyter 笔记本,我们首先需要用pip!pip安装它:

!pip install sidetable

然后导入它:

import pandas as pd
import sidetable

我们现在可以使用 stb 作为数据帧的存取器。我将使用 kaggle 上可用的美国汽车数据集。它包含了拍卖的二手车的数据。

df = pd.read_csv("/content/USA_cars_datasets.csv")#drop redundant columns
df.drop(['Unnamed: 0','vin','lot'], axis=1, inplace=True)df.head()

我们可能想看看主导品牌是什么。一种方法是使用value_counts功能。数据集中出现次数最多的 10 个品牌:

df.brand.value_counts()[:10]ford         1235 
dodge         432 
nissan        312 
chevrolet     297 
gmc            42 
jeep           30 
chrysler       18 
bmw            17 
hyundai        15 
kia            13 Name: brand, dtype: int64

我们可以通过使用归一化参数来获得频率比:

df.brand.value_counts(normalize=True)[:10]ford         0.494198 
dodge        0.172869 
nissan       0.124850 
chevrolet    0.118848 
gmc          0.016807 
jeep         0.012005 
chrysler     0.007203 
bmw          0.006803 
hyundai      0.006002 
kia          0.005202 Name: brand, dtype: float64

数据集中几乎 50%的汽车都是福特的。这比只看到计数更能提供信息。Sidetable 更进了一步。

df.stb.freq(['brand'])[:10]

Sidetable 返回每个品牌的计数和百分比以及累计值。肯定比**value_counts**信息量大。我们对数据集中的分布有了更多的了解。累积值的一个额外特性是我们可以设置累积百分比的阈值。然后,达到阈值后的类别被标记为“其他”。我们也可以使用 other_label 参数为“其他”指定一个标签。例如,我们可能希望看到构成数据集 90%的品牌。

df.stb.freq(['brand'], thresh=.9, other_label='other brands')

我们也可以通过多列,看到更具体的分布。让我们看看数据集中排名靠前的品牌年份组合。

df.stb.freq(['brand','year'], thresh=.5)

福特以 50%的份额在数据集中占据主导地位。大多数福特汽车都是 2019 款,占整个数据集的 19%。请注意,19%表示整个数据集中的比率,而不仅仅是福特品牌中的比率。为了获得福特品牌的分布情况,我们可以对数据帧应用过滤器。

df[df.brand == 'ford'].stb.freq(['year'], thresh=.9)

我们可以看到,2019 款福特汽车占所有福特品牌汽车的 38%。回想一下前面的例子,2019 款福特汽车占据了整个数据集的 19%。

sidetable 的另一个有用特性是它提供了基于值的分布。例如,我们可以检查每个品牌汽车的总价。要聚合的列被传递给参数。

df.stb.freq(['brand'], value='price', thresh=.95)

数据集中福特汽车的总价超过 2600 万,占所有汽车总价的 57%。回想一下前面的例子,数据集中 49%的汽车是福特品牌的。就总价而言,这一比例上升至 57%,表明福特汽车的平均价格高于其他品牌的平均价格。当然,还有其他因素会对价格产生影响,比如年份、里程、所有权状况等等。但是,它提供了一个一般的洞察力。

如果值的格式看起来不吸引人,可以使用样式参数进行更改。

df.stb.freq(['brand'], value='price', thresh=.95, style=True)

我认为熊猫的成功和流行来自于其多功能、强大且易于使用的操作和分析数据的功能。和熊猫一起完成一项任务几乎总是有多种方式。熊猫上添加的定制实用程序库优化了某些操作,并为熊猫带来了更多价值。再次感谢克里斯·莫菲特提供的这个有价值的工具。

由于花在数据科学项目上的大部分时间都花在了数据清理和预处理步骤上,Pandas 是您武库中的宝贵资产。

感谢您的阅读。如果您有任何反馈,请告诉我。

熊猫串操作—解释

原文:https://towardsdatascience.com/pandas-string-operations-explained-fdfab7602fb4?source=collection_archive---------19-----------------------

如何操作文本数据

Ashkan Forouzani 在 Unsplash 上的照片

我们必须用数值来表示每一位数据,以便由机器学习和深度学习模型进行处理和分析。然而,字符串通常不会有一个好的和干净的格式,需要大量的预处理。Pandas 提供了许多多功能函数来修改和处理字符串数据。在讨论字符串操作之前,最好提一下 pandas 是如何处理字符串数据类型的。

对象 vs 字符串

在 pandas 1.0 之前,只有“object”数据类型用于存储字符串,这导致了一些缺点,因为非字符串数据也可以使用“object”数据类型存储。Pandas 1.0 引入了一个新的特定于字符串数据的数据类型string type。到目前为止,我们仍然可以使用 object 或 string type 来存储字符串,但是在将来,我们可能会被要求只使用 string type。

这里需要注意的一点是,对象数据类型仍然是字符串的默认数据类型。要使用 StringDtype,我们需要显式声明它。

我们可以通过“字符串或 **pd。用于选择字符串数据类型的 Dtype 参数的 string type()**参数。

import pandas as pd
import numpy as np

另一种方法是使用 astype 函数转换为“字符串”。

字符串操作

  • 上下

谈到字符串,首先想到的是小写和大写字母。对 as 来说可能没什么大不了的,但是“A”和“A”就像“A”和“k”或任何其他字符对计算机来说一样不同。

**上()下()**的方法可以用来解决这个问题:

  • 剥离

如果字符串的开头或结尾有空格,我们应该修剪字符串以消除空格。剥离的方法可以用来做这个任务:

还有 lstriprstrip 方法分别删除前后空格。

  • 拆分

有时字符串携带不止一条信息。为了利用不同种类的信息,我们需要拆分字符串。而这里用的方法是分割,令人惊讶。

我们只需要将字符传递给 split。默认字符是空格或空字符串(str= ' '),所以如果我们要根据任何其他字符进行拆分,就需要指定它。

字符串被拆分,新元素被记录在一个列表中。通过传递索引,可以使用 []get 方法来访问列表中的元素。

我们也可以在拆分后用新元素创建一个数据帧。扩展参数设置为真创建一个数据帧。

如果一行没有足够的元素来匹配其他行,则单元格中不填充任何元素。我们也可以限制分裂的次数。默认情况下,分割从左边开始,但是如果我们想从右边开始,应该使用 rsplit

  • 卡特彼勒

正如我们在某些情况下需要拆分字符串一样,我们可能需要组合或连接字符串。 Cat 方法用于连接字符串。

我们需要使用 sep 参数传递一个参数放在连接的字符串之间。默认情况下,cat 忽略缺失值,但是我们也可以使用 na_rep 参数指定如何处理它们。

我们还可以进行元素级的连接(即向序列中的每个字符串添加一个字符串):

假设字符串是从左到右索引的,我们可以使用 str[] 访问每个索引。用例子来解释更好:

如果字符串没有指定的索引,则返回 NaN。

  • 开始和结束

我们可以分别使用以开头的和以结尾的来选择字符串。

  • 得到假人

我们可以从序列中提取虚拟变量。这在编码分类变量时特别有用。

这种表示需要将分类变量输入到机器学习模型中。

如果一个字符串包含多个值,我们可以首先使用 sep 参数进行拆分和编码:

  • 镜头

在某些情况下,我们需要数据帧的一系列或一列中字符串的长度。为了得到每个字符串的长度,我们可以应用 len 方法。请记住,len 也用于获取一个系列或数据帧的长度。让我们用例子来看看不同之处:

Pandas 字符串操作并不局限于我们在这里讨论的内容,但是我们讨论的函数和方法肯定会有助于处理字符串数据并加快数据清理和准备过程。

感谢阅读。如果您有任何反馈,请告诉我。

熊猫小贴士我希望我以前就知道

原文:https://towardsdatascience.com/pandas-tips-i-wish-i-knew-before-ef4ea6a39e1a?source=collection_archive---------8-----------------------

pivot 是如何工作的?熊猫的主要构件是什么?还有更多…

伊洛娜·弗罗利希在 Unsplash 上的照片

我成为熊猫超级用户已经有几年了。有时候我认为我已经掌握了它,但是几个月后我发现我像个菜鸟一样编程。我们都经历过😊我在这里与你分享的技巧是我最近学到的。

要运行示例,请下载这个 Jupyter 笔记本。

这里有几个你可能会感兴趣的链接:

- [Complete your Python analyses 10x faster with Mito](https://trymito.io/) [Product]- [Free skill tests for Data Scientists & ML Engineers](https://aigents.co/skills) [Test]- [All New Self-Driving Car Engineer Nanodegree](https://imp.i115008.net/c/2402645/1116216/11298)[Course]

你愿意阅读更多这样的文章吗?如果是这样,你可以点击上面的任何链接来支持我。其中一些是附属链接,但你不需要购买任何东西。

让我们从一个爆炸性的提示开始💥

从 giphy 下载的 Gif

熊猫有爆炸的功能。别担心,使用它是完全安全的😊当 DataFrame 列中存储有列表时,该函数非常有用。它解包列表中的值,并复制所有其他值,因此会爆炸💥

让我们创建一个 DataFrame,它的一列在列表中有随机数量的元素。

n = 10
df = pd.DataFrame({"list_col": [[random.randint(0, 10) for _ in range(random.randint(3, 5))] for _ in range(10)],}
)
df.shape(10, 1) # output

现在,让我们执行 explode 函数。

df = df.explode("list_col")
df.shape(40, 1) #output

在下表中,我们可以观察到由于从列表中解包值,索引被重复。

数据帧不是熊猫的主要构件

迷因创造了imgflip.com

Pandas 几乎是 DataFrames 的同义词,但如果我告诉你它不是它的主要构建块,你可能会感到惊讶。熊猫数据框架是建立在熊猫系列之上的。所以数据帧中的每一列都是一个系列。我们可以更深入,熊猫系列是基于什么?Numpy!但是我们不要走那么远。

当收益超过在项目中安装 pandas 的成本时,我甚至将 Python 的 list 包含在 pandas 系列中——我这里指的是后端,而不是分析项目。

让我们用窗口 2 计算一个列表中值的滚动和。

values = [1, 2, 0, 0, 0, 0, 1, 2, 3]
sr = pd.Series(values)
sr.rolling(2).sum()

这样代码就更简洁了。

Pivot —数据科学家的必备工具

从 giphy 下载的 Gif

什么是支点?数据透视表是一个统计表,它汇总了一个更广泛的表中的数据。听起来很有用!让我们试一试。

假设我们有一家水果店和几个顾客。

df = pd.DataFrame({"fruit": ["apple", "orange", "apple", "avocado", "orange"],"customer": ["ben", "alice", "ben", "josh", "steve"],"quantity": [1, 2, 3, 1, 2],}
)

现在,让我们用 fruit 和 customer 列以及聚合数量值来透视表。我们期待一张桌子,水果在一个轴上,顾客在另一个轴上。应合计数量值

df.pivot(index="fruit", columns="customer", values="quantity")

我们得到一个“值错误:索引包含重复条目,无法整形”。这是什么意思?

让我们用一个不同的命令(但是更容易解释)来尝试 pivot,它与 pivot 函数具有相同的效果。

df.set_index(["fruit", "customer"])["quantity"].unstack()

该命令返回与 pivot 函数相同的错误,但是更清楚幕后发生了什么。水果列和客户列组合在一起时似乎没有唯一的索引。

现在,让我们尝试使用 pivot_table 函数,这也是推荐的方法。注意,该函数还支持 aggfunc,默认情况下是 np.mean。我们在下面的例子中使用 np.sum。

df.pivot_table(index="fruit", columns="customer", values="quantity", aggfunc=np.sum)

很少值得一提

从 giphy 下载的 Gif

访问元素

访问数据帧中的第一个元素(和最后一个元素)非常简单:

df = pd.DataFrame({"col": [1, 2, 3, 4, 5]})df.iloc[0]df.iloc[-1] # the last element

你可能会问 loc 和 iloc 有什么区别?当通过索引访问行时,我们使用 loc,其中索引可以是字符串、整数或其他类型。

我们还使用 loc 在某个索引上设置一个新的列值(我们不能用 iloc 这样做—它会返回 ValueError):

df.loc[0, "col"] = 1

追加值

Pandas 有一个 append 函数,使您能够将值追加到数据帧中。但是技巧是附加的值也需要在数据帧中。

df = df.append(pd.DataFrame({'col': [999]}))
df

行到列

我最喜欢的将行变成列的方法是使用转置。它在 numpy 中也有效。

df.T

在你走之前

在推特上关注我,在那里我定期发关于数据科学和机器学习的推特。

照片由Courtney hedge在 Unsplash 上拍摄

熊猫给你的建议会让你省去几个小时的挠头时间

原文:https://towardsdatascience.com/pandas-tips-that-will-save-you-hours-of-head-scratching-31d8572218c9?source=collection_archive---------8-----------------------

从长远来看,使您的数据分析实验具有可重复性可以为您和他人节省时间

当重新审视你过去处理过的问题时,发现代码不起作用是令人沮丧的。从长远来看,使您的数据分析实验具有可重复性可以为您和他人节省时间。这些提示将帮助您编写可重复的 pandas 代码,当您在团队中工作时,这对于您计划在未来重新访问或与其他人共享的个人项目非常重要。

要运行示例,请下载这个 Jupyter 笔记本。

这里有几个你可能会感兴趣的链接:

- [Labeling and Data Engineering for Conversational AI and Analytics](https://www.humanfirst.ai/)- [Data Science for Business Leaders](https://imp.i115008.net/c/2402645/880006/11298) [Course]- [Intro to Machine Learning with PyTorch](https://imp.i115008.net/c/2402645/788201/11298) [Course]- [Become a Growth Product Manager](https://imp.i115008.net/c/2402645/803127/11298) [Course]- [Deep Learning (Adaptive Computation and ML series)](https://amzn.to/3ncTG7D) [Ebook]- [Free skill tests for Data Scientists & Machine Learning Engineers](https://aigents.co/skills)

上面的一些链接是附属链接,如果你通过它们购买,我会赚取佣金。请记住,我链接课程是因为它们的质量,而不是因为我从你的购买中获得的佣金。

要升级你的熊猫游戏,请阅读:

[## 熊猫分析服务器

一个开源项目,简化了熊猫与实时数据的连接,测试假设和可视化…

towardsdatascience.com](/pandas-analytics-server-d9abceec888b)

输出版本

为了使您的 pandas 实验可重复,从输出系统信息和 python 包的版本开始。你(或你的同事)可以以后再感谢我。在某个包的旧版本中,某些功能可能被弃用、损坏或不可用。注意,Python 包是特意用==打印出来的,这样您就可以直接使用 pip 的输出来安装它们。

我使用下面的模板来输出系统信息和包的版本。

import os
import platform
from platform import python_versionimport jupyterlab
import numpy **as** np
import pandas **as** pd**print**("System")
**print**("os name: %s" **%** os**.**name)
**print**("system: %s" **%** platform**.**system())
**print**("release: %s" **%** platform**.**release())
**print**()
**print**("Python")
**print**("version: %s" **%** python_version())
**print**()
**print**("Python Packages")
**print**("jupterlab==%s" **%** jupyterlab**.**__version__)
**print**("pandas==%s" **%** pd**.**__version__)
**print**("numpy==%s" **%** np**.**__version__)

对自动导入说不

我曾经有过一个很棒的想法,不要每次都写。Jupyter 笔记本可以自动导入它们。

听起来很棒?嗯,结局不太好。过了一会儿,我忘记了我的定制配置,不久之后我就收到了类似这样的问题:“你运行代码了吗,因为它在第一行就失败了!”,“这段代码在你的机器上是如何工作的?”。

对自动进口说不。

播种

使用随机生成的数据时,必须设置种子。如果您正在使用机器学习模型,您还应该设置随机种子(如果可用),以便模型返回确定性输出。

让我们看看例子。我们设置随机种子并输出一个包含 10 个伪随机数的随机样本。正如所料,第二次运行与第一次运行有不同的伪随机数。注意,熊猫在引擎盖下使用 numpy,所以我们需要用 numpy 设置种子。

np**.**random**.**seed(42)np**.**random**.**random_sample(10)# Outputarray([0.37454012, 0.95071431, 0.73199394, 0.59865848, 0.15601864,0.15599452, 0.05808361, 0.86617615, 0.60111501, 0.70807258]) np**.**random**.**random_sample(10)# Outputarray([0.02058449, 0.96990985, 0.83244264, 0.21233911, 0.18182497,0.18340451, 0.30424224, 0.52475643, 0.43194502, 0.29122914])

当我们再次设定相同的种子时会发生什么?我们重置种子,得到与上面相同的数字序列。这使得确定性伪随机数发生器。

np**.**random**.**seed(42)np**.**random**.**random_sample(10)# Outputarray([0.37454012, 0.95071431, 0.73199394, 0.59865848, 0.15601864,0.15599452, 0.05808361, 0.86617615, 0.60111501, 0.70807258])

评论

一个有 10 行 pandas 代码的代码块很可能被一个 pandas 专家重写为 5 行,但是代码的可理解性受到影响。随着工具越来越好,我们也倾向于做同样的事情。今天我们可能知道代码做了什么,但是一个月后我们会记得吗?初级分析师会知道这是什么吗?

大概不会!当代码变得复杂时,你应该写一两条注释。不只是在用熊猫做数据分析的时候,而是在一般编码的时候。

安全检查

写安全检查而不是注释,比如“这部分代码不支持空值或重复”。这将花费相同的时间,但是用户肯定会注意到安全检查,因为在出现问题的情况下,它们会中断执行。

让我们看看下面的例子。

df **=** pd**.**DataFrame(index**=**[1, 2, 3, 4, 4], data**=**{"col1": ["a", "b", "c", "d", "d"]})

数据帧具有重复的索引值 4。我们可以使用重复的函数来检测重复的索引,然后用 assert 语句中断执行。

**assert** len(df[df**.**index**.**duplicated()]) **==** 0, "Dataframe has duplicates" 

格式化代码

Jupyter 笔记本因无格式、丑陋的代码而臭名昭著。主要原因是早期版本没有代码格式化程序。在他们这样做之后,安装它们就不是一件小事了。但现在情况不同了。

我将 jupyterlab-code-formatter 与 jupyterlab 一起使用,效果很好。这里是安装指南。如果你需要任何安装帮助,请在评论中告诉我。

格式正确的代码会增加你不扔掉它重新开始的机会。

输出数据帧的形状

我发现在每次转换后输出数据帧的形状是一个很好的实践。这有助于在读取、合并等操作后发现错误的行数或列数。这样,我们只需检查 shape 函数的输出就可以发现错误,而无需重新运行笔记本。

让我们将示例数据帧与其自身进行内部连接。它只有 5 行,所以我们希望新的数据帧也有 5 行。

df**.**shape(5, 1)

新数据帧有 7 行,而不是 5 行。

df_new **=** df**.**join(df, lsuffix**=**'_l', rsuffix**=**'_r')
df_new**.**shape(7, 2)

我们看到问题的出现是因为一个重复的索引。通过使用 shape 函数,我们可以立即发现一个 bug。

df_new

提出可重复的问题

有些情况下,我们有输入数据,我们知道输出应该是什么样子,但我们不知道如何编写中间的步骤(我们都经历过)。下一步通常是询问关于堆栈溢出或 Reddit 的问题,或者向同事寻求帮助。

通过编写可重复的问题,我们可以使协作解决问题变得更加容易:

  • 简明扼要地描述问题的核心,不要通过复制粘贴实验的一半而陷得太深,
  • 使用可以在单行中初始化的小数据帧(不要引用本地数据集),
  • 使用 slack 时,用``将代码块中的代码换行。

一个好的做法是使 DataFrame 输出易于复制粘贴。没听说过?我举个例子解释一下。

df# Copy-paste output col1
1	a
2	b
3	c
4	d
4	d

Pandas 有一个 read_clipboard 方法,顾名思义就是这样做的。我们可以复制上面的输出并运行下面的命令,它将复制数据帧。你自己试试。如果需要,我们也可以将分隔符更改为制表符\t或任何其他分隔符。

df **=** pd**.**read_clipboard(sep**=**'\s\s+')
df

这个复制-粘贴过程不适用于 MultiIndex。所以提问的时候尽量避开他们。

结论

这些是让你的熊猫实验可重复的几个小技巧。你喜欢这个职位吗?请在下面的评论中告诉我。

在你走之前

在推特上关注我,在那里我定期发关于数据科学和机器学习的微博。

照片由Courtney hedge在 Unsplash 上拍摄

熊猫在每个城镇寻找最可爱的猫

原文:https://towardsdatascience.com/pandas-to-look-for-the-cutest-cat-per-town-fbaffc7363c9?source=collection_archive---------54-----------------------

蔡文许在 Unsplash 上的原图,本人编辑。

熊猫的有趣介绍——Python 数据分析库

嗨,在的上一篇文章中,我们看到了使用 SQL 和 Elasticsearch 解决典型的每组最大数量的问题。本文将探讨如何使用强大的 Python 数据分析库 Pandas 来解决这个问题。🐼

熊猫得到了两个重要的数据结构系列和数据帧。我们将探索 Pandas DataFrame 数据结构和它的一些功能来解决我们的问题。说问题,没看过上一篇的我来解释一下。在一个城镇里,会有许多可爱的猫。我们要从每个镇只挑一只最可爱的猫,它的名字叫喵(或者类似喵,以后会看到)。

如果你想跟进,我建议你参考熊猫官方网站进行本地设置,或者你可以在 Kaggle 上创建一个新的笔记本。甚至提交你的 Kaggle 找喵任务的解决方案。

让我们用一个小的猫的数据集,列 id,猫的名字,城镇,可爱程度从 1 到 10,10 是最可爱的。

资料组

该数据集的预期输出为:

预期结果

首先,我们将 pandas 库作为pd导入,并用样本数据集创建一个数据帧df。有许多方法可以创建数据帧。下面我提供了三个选项。选项 1 使用字典;选项 2,通过加载本地可用的 CSV 文件;选项 3 从 URL 读取 CSV 文件。

一旦创建了数据帧,就可以使用df.head()方法从数据帧中获取前 5 行。可选地,您可以传递要检索的行数,比如df.head(10),检索前 10 行。

创建数据框架

类似于df.head(n)方法,有df.tail(n)返回最后 n 条记录。

df.tail()

df.columns将返回所有的列名。
df.shape返回表示数据帧维度的元组。比如我们的 DataFrame,(10,4),这意味着 10 行 4 列。
df.size返回一个表示该对象中元素个数的 int。比如我们的数据帧,40 (10*4)

数据帧信息

为了获得数据帧的简明摘要,我们可以使用df.info()。我们的数据有 4 个非空列,每个列有 10 个条目。idcuteness为表示数字的int64数据类型。nametown作为一个object。如果您正在处理一些未知的数据,这可能是方便的信息。

其中df.info提供关于数据类型、内存使用等的信息。,我们可以使用df.describe()来获得统计数据。你可以参考官方的文件来理解这些数字的含义。

数据帧描述

要引用特定的列数据,您可以像df['town']一样访问并对其执行查询。想要获得列 town 的唯一值,我们可以运行df['town'].unique()。或者获取每个城镇的值计数,df['town'].value_counts()。根据我们的数据,我们在德里有 4 只猫,在孟买和班加罗尔各有 2 只猫& Meerut,我们必须在每个城镇中找出 1 只最可爱的猫。

唯一计数

要查看每个城镇每列的最大值,我们可以按城镇对数据进行分组,并使用 max 函数。如果你看下面的结果,乍一看,它可能似乎是我们问题的解决方案(忽略名称条件),但它肯定不是。像我前面说的,它分别返回每一列的最大值**。如您所见,我们没有 id 和姓名为 5、tom 可爱度为 10 的记录。尽管我们在班加罗尔的最大 id 是 8。同样,在密鲁特和孟买,9 是最大的可爱。**

最大

要找到名为喵的猫,我们必须添加过滤器。我们可以通过多种方式查询数据。比如df[df['name']=='meow']或者使用df.query()执行字符串查询。本文将使用前一个。但是,在某些情况下,后一种方法可能更有用,比如您从一些外部来源获取这些查询。

询问

根据我们的任务,我们不仅要寻找猫名"喵",还要寻找听起来相似的猫名。所以将修改我们的搜索查询来查找包含喵的名字。我们将如何使用.str将列转换为字符串,并使用字符串的 contains 方法。看看下面的搜索结果,现在我们有了猫的子集,它们的名字叫喵或者听起来像喵。

包含查询

对于猫的子集,让我们按城镇将它们分组,并找出每个城镇的最大可爱程度。这给了我们每个城镇最大的可爱度,但是我们还没有从这个结果中识别出猫。我们丢失了一些列,如 id 和 name。

分组依据

因此,不是取出可爱列并对其应用一个max函数,而是对整个DataFrameGroupBy对象应用一个 lambda 函数,返回一个以城镇为索引的数据帧。如果你检查下面的结果,现在我们有城镇作为一个列和一个索引。

分类

现在有了这个数据框架,我们可以再次按城镇分组,并从每个组中获得第一个条目,这就是我们的解决方案。但是如果我们这样做,我们会得到一个异常,因为town既是一个索引级别又是一个列标签,这是不明确的。

错误

我们能做的是在做另一个 group by 之前重置索引。我们可以在df.reset_index(drop**=**True)前完成。drop=True选项将避免索引作为一列添加到结果数据帧中。或者更好的是,我们可以使用groupby方法的现有选项as_index=False,这将产生类似的结果。

看看下面的解决方案,我们可以在每个城镇找到名字为喵或与之相似的最可爱的猫。

但是它与我们预期的解决方案不匹配😳。对于德里,我们期待 id 为 5 的猫,而不是 3。我们遗漏了任务的一部分,我们必须优先选择名字叫喵的猫,而不是名字听起来像喵的猫。

解决办法

为此,一种方法是我们添加另一个得分字段。假设猫的名字不能超过 100 个单词,我们可以使用公式(cuteness of cat * 100) — length of the name给每只猫打分。所以即使两只猫的可爱度都是 10。喵喵猫会得分10*100-4 = 996,卡米诺会得分10*100-6 = 994。有趣的是,我们的分数不会因为可爱程度不同而重叠。比如,如果可爱度是 10,分数将在范围10*100-100 = 90010*100-4 = 996之间。如果可爱度是 9,分数将在9*100-100 = 8009*100-4 = 896的范围内。所以我们可以安全地使用这个公式。

要向我们的 DataFrame 添加一个新列,我们可以简单地做如下的事情。

新列

所以现在对于我们的最终解决方案,我们可以用可爱度排序代替 total _ score,我们得到了正确的结果。🤗

最终解决方案

感谢阅读!如果你有任何疑问或者你觉得你知道一个更好的方法来“找到喵”,请发表评论

页(page 的缩写)准备好迎接每镇最可爱的猫挑战了吗?在推特上发布你对熊猫的最佳解决方案,标签为# 每镇最可爱的猫,#findingmeow 👨‍💻或者下面评论。如果我们发现您的解决方案比我们的更好,我们将附上您的姓名和您提交的内容。

熊猫输入缺失数据的技巧

原文:https://towardsdatascience.com/pandas-tricks-for-imputing-missing-data-63da3d14c0d6?source=collection_archive---------5-----------------------

用熊猫输入数据

来源

数据科学家面临的最大挑战之一是处理缺失数据。在本帖中,我们将讨论如何使用熊猫来估算缺失的数值和分类值。

我们开始吧!

出于我们的目的,我们将使用葡萄酒杂志数据集,它可以在这里找到。

首先,让我们将数据读入熊猫数据框:

import pandas as pd 
df = pd.read_csv("winemag-data-130k-v2.csv")

接下来,让我们使用。head()'方法:

print(df.head())

因为我们对输入缺失值感兴趣,所以查看缺失值在各列中的分布会很有用。

我们可以用'来显示丢失的值信息。“info()”方法。这将显示每列中非空值的数量:

print(df.info())

我们也可以使用。isnull()“和”。sum()'方法计算每列中缺失值的数量:

print(df.isnull().sum())

我们看到生成的 Pandas 系列显示了数据中每一列的缺失值。“价格”列包含 8996 个缺失值。我们可以使用'替换这些丢失的值。fillna()”方法。例如,让我们用平均价格填充缺失值:

df['price'].fillna(df['price'].mean(), inplace = True)
print(df.isnull().sum())

我们看到“价格”列不再有缺失值。现在,假设我们想做一个更精确的估算。一个好的猜测是用缺少的值所属国家的平均价格替换价格列中缺少的值。例如,如果我们考虑意大利葡萄酒缺失的葡萄酒价格,我们可以用意大利葡萄酒的平均价格替换这些缺失的值。接下来,让我们看看“国家”值的分布。我们可以使用集合模块中的“Counter”方法来实现:

from collections import Counter
print(Counter(df['country']))

让我们来看看美国制造的葡萄酒。我们可以定义一个只包含“美国”葡萄酒的数据框:

df_US = df[df['country']=='US']

现在,让我们打印缺失值的数量:

print(df_US.isnull().sum())

我们看到在“美国”葡萄酒数据中有 239 个缺失的“价格”值。为了用对应于美国价格的平均值填充缺失值,我们执行以下操作:

df_US['price'].fillna(df_US['price'].mean(), inplace = True)

现在,假设我们想对每个国家缺失的价格值进行这样的计算。首先,让我们估算缺失的国家值:

df['country'].fillna(df['country'].mode()[0], inplace = True)

接下来,在 for 循环中,我们可以定义特定于国家的数据帧:

for i in list(set(df['country'])):df_country = df[df['country']== country]

接下来,我们可以用相应的平均价格来填充这些国家特定数据框中缺失的值:

for i in list(set(df['country'])):df_country = df[df['country']== country]df_country['price'].fillna(df_country['price'].mean(),inplace = True)

然后,我们将结果附加到一个我们称之为“帧”的列表中

frames = []
for i in list(set(df['country'])):df_country = df[df['country']== country]df_country['price'].fillna(df_country['price'].mean(),inplace = True)frames.append(df_country)

最后,我们连接数据帧的结果列表:

frames = []
for i in list(set(df['country'])):df_country = df[df['country']== i]df_country['price'].fillna(df_country['price'].mean(),inplace = True)frames.append(df_country)final_df = pd.concat(frames)

现在,如果我们在估算前打印缺失价格值的数量,我们得到:

print(df.isnull().sum()) 

插补后:

print(final_df.isnull().sum())

我们看到除了一个缺失值之外,所有的值都被估算了。这对应于没有价格数据的埃及葡萄酒。我们可以通过检查 for 循环中数据帧的长度来解决这个问题,如果长度大于 1,则只使用特定于国家的平均值进行输入。如果长度等于 1,我们估算所有国家的平均值:

frames = []
for i in list(set(df['country'])):df_country = df[df['country']== i]if len(df_country) > 1:    df_country['price'].fillna(df_country['price'].mean(),inplace = True)        else:df_country['price'].fillna(df['price'].mean(),inplace = True)frames.append(df_country)    final_df = pd.concat(frames)

打印结果时,我们看到“价格”列的所有值都是估算的:

print(final_df.isnull().sum())

我们可以定义一个函数来概括这个逻辑。我们的函数将接受对应于数字列和分类列的变量:

def impute_numerical(categorical_column, numerical_column):frames = []for i in list(set(df[categorical_column])):df_category = df[df[categorical_column]== i]if len(df_category) > 1:    df_category[numerical_column].fillna(df_category[numerical_column].mean(),inplace = True)        else:df_category[numerical_column].fillna(df[numerical_column].mean(),inplace = True)frames.append(df_category)    final_df = pd.concat(frames)return final_df

我们通过执行以下操作,使用我们的函数进行插补:

impute_price  = impute_numerical('country', 'price')
print(impute_price.isnull().sum())

我们还要验证原始数据框和估算数据框的形状是否匹配

print("Original Shape: ", df.shape)
print("Imputed Shape: ", impute_price.shape)

类似地,我们可以定义一个估算分类值的函数。该函数将接受两个变量,这两个变量对应于具有分类值的列。

def impute_categorical(categorical_column1, categorical_column2):cat_frames = []for i in list(set(df[categorical_column1])):df_category = df[df[categorical_column1]== i]if len(df_category) > 1:    df_category[categorical_column2].fillna(df_category[categorical_column2].mode()[0],inplace = True)        else:df_category[categorical_column2].fillna(df[categorical_column2].mode()[0],inplace = True)cat_frames.append(df_category)    cat_df = pd.concat(cat_frames)return cat_df

我们可以用各个国家/地区的模式来估算缺失的“taster_name”值:

impute_taster = impute_categorical('country', 'taster_name')
print(impute_taster.isnull().sum())

我们看到“taster_name”列现在没有缺失值。同样,让我们验证形状是否与原始数据框匹配:

print("Original Shape: ", df.shape)
print("Imputed Shape: ", impute_taster.shape)

我就讲到这里,但是您可以随意使用数据并自己编码。

结论

总之,在这篇文章中,我们讨论了如何使用 Pandas 库处理缺失值。首先,我们讨论了如何用数据的平均值来估算缺失的数值。然后,我们研究了如何进行特定类别的数值插补。最后,我们展示了如何用对应于另一个分类列的模式来估算缺失的分类值。我希望你觉得这篇文章有用/有趣。这篇文章中的代码可以在 GitHub 上找到。感谢您的阅读!

加快数据分析过程的熊猫技巧

原文:https://towardsdatascience.com/pandas-tricks-that-expedite-data-analysis-process-e941dbfc3e75?source=collection_archive---------43-----------------------

用这些简单的技巧加速你的数据分析过程。

Pandas 是一个非常强大和通用的 Python 数据分析库,它加速了数据科学项目的预处理步骤。它提供了许多在数据分析中非常有用的函数和方法。

张家瑜在 Unsplash 上拍照

一如既往,我们从进口熊猫开始。

import numpy as np
import pandas as pd

让我们创建一个样本数据帧来处理。Pandas 是一个多功能库,通常提供多种方式来完成一项任务。因此,有许多方法可以创建数据帧。一种常见的方法是传递包含列作为键值对的字典。

values = np.random.randint(10, size=10)years = np.arange(2010,2020)groups = ['A','A','B','A','B','B','C','A','C','C']df = pd.DataFrame({'group':groups, 'year':years, 'value':values})df

我们还使用 numpy 创建数组,用作列中的值。 np.arange 返回指定区间内的范围值。 np.random.randint 根据指定的范围和大小返回随机整数值。

数据框架包含 3 个不同组的一些年值。我们可能只对每年的值感兴趣,但在某些情况下,我们也需要一个累计和。Pandas 提供了一个简单易用的函数来计算累计和,即 cumsum

df['cumsum'] = df['value'].cumsum()df

我们创建了一个名为“cumsum”的列,它包含值列中数字的累积和。但是,它不考虑群体。这种累积值在某些情况下可能没有用,因为我们无法区分不同的组。放心吧!这个问题有一个非常简单方便的解决方案。我们可以应用 groupby 函数。

df['cumsum'] = df[['value','group']].groupby('group').cumsum()df

我们首先对“组”列应用 groupby ,然后应用 cumsum 函数。现在,每组内的值相加。为了使数据框看起来更好,我们可能希望根据组而不是年份对值进行排序,这样我们可以直观地将组分开。

df.sort_values(by='group').reset_index()

我们应用了 sort_values 函数,并用 reset_index 函数重置索引。正如我们在返回的数据帧中看到的,原始索引作为一列保存。我们可以通过将 reset_index 函数的 drop 参数设置为 True 来消除。

df = df.sort_values(by='group').reset_index(drop=True)df

现在看起来好多了。当我们想在数据帧中添加一个新列时,默认情况下它会被添加到末尾。然而,pandas 提供了使用插入功能在任意位置添加新列的选项。

new = np.random.randint(5, size=10)df.insert(2, 'new_col', new)df

我们通过传递一个索引作为第一个参数来指定位置。该值必须是整数。列索引从零开始,就像行索引一样。第二个参数是列名,第三个参数是包含值的对象,这些值可以是系列或类似数组的对象。

假设我们想从数据帧中删除一列,但又想将该列保留为一个单独的序列。一种方法是将该列分配给一个系列,然后使用 drop 功能。更简单的方法是使用 pop 功能。

value = df.pop('value')df

通过一行代码,我们从 dataframe 中删除了 value 列,并将其存储在 pandas 系列中。

我们有时需要根据条件过滤数据帧或应用掩码来获得某些值。过滤数据帧的一个简单方法是查询函数。我将使用我们一直使用的样本数据框架。让我们首先将“值”列插回:

df.insert(2, 'value', value)df

使用查询函数非常简单,只需要条件。

df.query('value < new_col')

它返回“值”小于“新列”的行。我们可以设置更复杂的条件,也可以使用额外的操作符。

df.query('2*new_col > value')

我们还可以将多个条件组合成一个查询。

df.query('2*new_col > value & cumsum < 15')

我们可以使用许多聚合函数来计算列的基本统计信息,如平均值、总和、计数等。我们可以将这些函数中每一个应用于一个列。然而,在某些情况下,我们可能需要检查不止一种类型的统计数据。例如,在某些情况下,计数和平均值可能都很重要。pandas 没有单独应用函数,而是提供了 agg 函数来应用多个聚合函数。

df[['group','value']].groupby('group').agg(['mean','count'])

既看均值又看计数更有意义。我们可以很容易地检测出异常值,这些异常值具有极端的平均值,但观察次数非常少。

我认为熊猫的成功和流行来自于其多功能、强大且易于使用的操作和分析数据的功能。和熊猫一起完成一项任务几乎总是有多种方式。由于花在数据科学项目上的大部分时间都花在了数据清理和预处理步骤上,Pandas 是您武库中的宝贵资产。

感谢您的阅读。如果您有任何反馈,请告诉我。

Pandas vs SQL —与示例进行比较

原文:https://towardsdatascience.com/pandas-vs-sql-compared-with-examples-3f14db65c06f?source=collection_archive---------8-----------------------

如何使用这两者完成数据分析中的典型任务

咖啡极客在 Unsplash 上的照片

Pandas 是一个用于数据分析和操作的 Python 库。SQL 是一种用于与数据库通信的编程语言。大多数关系数据库管理系统(RDBMS)使用 SQL 来操作存储在数据库中的表。它们的共同点是 Pandas 和 SQL 都操作表格数据(即表格由行和列组成)。

熊猫和 SQL 都是数据科学家和分析师的必备工具。当然,两者都有替代方案,但它们是这一领域的主导方案。

因为 Pandas 和 SQL 都是对表格数据进行操作的,所以类似的操作或查询都可以使用这两者来完成。在这篇文章中,我们将比较 Pandas 和 SQL 在数据分析过程中的典型操作。

我们将使用 Kaggle 上的客户流失数据集。

对于熊猫,我会用 Google Colab。将 csv 文件上传到 Colab 环境后,数据集被读入 pandas 数据帧。

import pandas as pd
churn = pd.read_csv("/content/churn.csv")

对于 SQL,我在 Amazon RDS 上创建了一个 MySQL 数据库,并使用 MySQL Workbench 将连接到它。建立连接后,我创建了一个名为“CHURN”的表,并将 csv 文件中的数据上传到该表中。您可以通过在 MySQL Workbench 中运行以下 SQL 语法来完成相同的操作。

CREATE TABLE CHURN (
RowNumber INT NOT NULL,
CustomerId INT NOT NULL,
Surname VARCHAR(20) NULL,
CreditScore INT NULL,
Geography VARCHAR(20) NULL,
Gender VARCHAR(20) NULL,
Age INT NULL,
Tenure INT NULL,
Balance DECIMAL(10,2) NULL,
NumOfProducts INT NULL,
HasCrCard INT NULL,
IsActiveMember INT NULL,
EstimatedSalary DECIMAL(10,2) NULL,
Exited INT NULL,
PRIMARY KEY(RowNumber)
);LOAD DATA LOCAL INFILE "C:/Users/soner/Desktop/SQL/churn.csv" INTO TABLE CHURN 
FIELDS TERMINATED by ','
ENCLOSED by '"'
LINES TERMINATED by '\n' IGNORE 1 LINES;

注意:如果使用最新版本(8。)的话,上面的 load data 语句就不起作用了。我用的是 6 版。

我们现在有了一个客户流失数据框架和一个客户流失表。让我们从数据分析过程中常见的基本操作开始。

获取数据概述

这里概述的含义有点模糊。这里我指的是列及其数据类型的列表。

DESC 语句后跟表名将在 SQL 中完成这项工作。

DESC CHURN;

(图片由作者提供)

对于熊猫,“dtypes”方法将返回每一列的数据类型。我们还可以使用“columns”方法来查看列的列表。

churn.dtypes

(图片由作者提供)

显示前 5 行

这也可以被认为是获得数据的概述。数字 5 只是惯例,但是你可以改变它。

在 SQL 方面,我们将使用 SELECT 语句。

SELECT * FROM CHURN LIMIT 5;

(图片由作者提供)

我们选择了所有列(*)的前 5 行(限制为 5 行)。该屏幕截图仅包含 7 列,因此很适合屏幕。

不是每个 DBMS 都有相同的语法。我们这里用的是 MySQL。例如,SQL Server 使用 SELECT TOP 语句。

Pandas 为这个操作提供了一个更简单的语法。

churn.head(5) # The default is 5 so churn.head() also works

(图片由作者提供)

选择特定的列

对于 SQL,我们只需要用列名替换“*”。

SELECT CustomerId, Geography FROM CHURN;

(图片由作者提供)

对熊猫来说是这样做的。

churn[['CustomerId', 'Geography']]

(图片由作者提供)

选择符合条件的行

在分析数据时,我们可能会考虑一些条件。例如,在我们的数据集中,任务可能是基于一些测量来比较不同的国家。因此,能够有条件地选择数据点非常重要。

我们可以在 SQL 中使用 WHERE 语句。例如,以下查询将返回“地理位置”列中的值为“法国”的选定列。

SELECT CustomerId, Geography FROM CHURN
WHERE Geography = 'France'
LIMIT 5;

(图片由作者提供)

对于 Pandas,根据条件过滤数据帧,然后选择所需的列和行。

churn[churn.Geography == 'France'][['CustomerId','Geography']][:5]

(图片由作者提供)

列中的唯一值

分析分类列和数字列是很重要的。分类列的一个关键特征是唯一的类别。

让我们看看在地理位置一栏中有哪些国家。

SELECT DISTINCT 语句将返回表中的不同值。

SELECT DISTINCT Geography FROM CHURN;

(图片由作者提供)

同样的操作可以用熊猫特有的功能来完成。

churn.Geography.unique()
array(['France', 'Spain', 'Germany'], dtype=object)

列中唯一值的数量

在地理栏中,只有 3 个不同的国家,所以我们可以直观地计算。在某些情况下,独特类别的数量很大,所以我们需要一种方法来计算它们。

对于 SQL,我们可以如下使用 COUNT 语句:

SELECT COUNT(DISTINCT Geography) FROM CHURN;
3

对于熊猫,nunique 函数将完成这项工作。

churn.Geography.nunique()
3

每个类别中的行数

我们已经介绍了如何检查唯一类别和唯一类别的数量。更进一步,查看每个类别有多少数据点(即行数)可能更有用。

对于 SQL,可以使用 COUNT 和 GROUP BY 语句来完成,如以下查询所示:

SELECT Geography, COUNT(Geography) AS 'count' 
FROM CHURN
GROUP BY Geography;

(图片由作者提供)

我们选择了两列,一列是 Geography,另一列是 Geography 列中的行数。如果末尾没有“GROUP BY”语句,查询将返回一行,指示表中的总行数。

熊猫的 value_counts 函数可以完成同样的任务。

churn.Geography.value_counts()

(图片由作者提供)

分组和聚合函数

SQL 和 Pandas 都允许对查询结果应用聚合函数,这对于高效的数据分析非常重要。

例如,我们可以检查不同国家客户的平均年龄。下面的 SQL 查询将完成这项任务,它还将根据平均年龄值对结果进行排序。

SELECT Geography, AVG(Age) AS 'Average Age' 
FROM CHURN
GROUP BY Geography
ORDER BY Age;

(图片由作者提供)

熊猫遵循相同的想法,只是语法不同。

churn[['Geography','Age']].groupby('Geography').mean()\
.sort_values(by='Age', ascending=False)

(图片由作者提供)

结论

我们只介绍了 Pandas 或 SQL 的一小部分功能。然而,这些操作对于典型的数据分析过程是必不可少的。我认为它们是学习复杂操作所必须掌握的基础。

正如您在示例中看到的,Pandas 和 SQL 背后的逻辑非常相似。一旦你熟悉了其中的一种,学习另一种就相当容易了。这只是一个语法问题。

如果你正在从事或者打算从事数据科学领域的工作,我强烈推荐你学习熊猫和 SQL。

感谢您的阅读。如果您有任何反馈,请告诉我。

熊猫!!!第一次现场技术面试后我学到了什么

原文:https://towardsdatascience.com/pandas-what-ive-learned-after-my-1st-on-site-technical-interview-4fb94dbc1b45?source=collection_archive---------12-----------------------

技术面试

关于熊猫 str 关键文本清洗技巧的思考

前言

我知道很多人在面试时会紧张。同样,在我的面试中,10 次有 8 次我会坐立不安。这意味着忘记我口袋里的常用技巧,或者错过一些我应该知道的关键知识。最近,我参加了一个商业智能实习职位的现场技术面试,你猜怎么着?全是:熊猫!虽然采访没有我想象的那么顺利,但我想把这次经历转变成对我认为对熊猫至关重要的事情的反思,特别是文本数据处理。

由 Unsplash 上车头拍摄

概观

本文将介绍在 Pandas 、**、**中处理文本数据的主要功能。Series.str "。大部分问题设置和我面试时经历的差不多。当你阅读这篇文章时,你将有机会回顾你所学到的东西,如果你期待一次技术面试,你将会收到一个友好的提醒。如果您是熊猫的新手,我希望您可以将本文中展示的技巧添加到您的数据科学工具包中。让我们开始朝着更加结构化的数据前进。

[## 每当张彝伦出版的时候收到一封电子邮件。

每当张彝伦出版的时候收到一封电子邮件。或者督促他多发表!!!通过注册,您将创建一个媒体…

medium.com](https://medium.com/subscribe/@yunglinchang)

台北动物园的熊猫,来源:我

仅供参考:

  • 这篇文章将被分成小的问题集和这些问题之后可能的解决方案(或者我用来解决每个问题的方法)。
  • 这个数据集是一个虚构的“水果”公司的销售数据,用来说明你在面试、工作或数据项目中可能遇到的挑战。

“水果”公司的销售数据,来源:我

  • 数据被预加载并保存在 df 中,并且不要忘记:
import pandas as pd

事不宜迟,我们开始吧!

首先,面试官给了你一份水果销售部门的数据集。你被要求用你的 Python 技术能力解决每一个专栏中的问题。你发现了什么?

Sales_ID:怪异的感叹号和多余的空格

如果我们看一下 Sales_ID 列的第一行,您会发现它包含不必要的空格和一个感叹号。这是一个问题,因为在 Sales_ID 列中我们不需要那些多余的字符。

df[ 'Sales_ID'][0]**Out: 'AU_1382578        !'**

我们能做的就是利用 **熊猫。**中的法熊猫! strip() 修剪掉列的前导和尾随字符。还有类似于右条带的 rstrip() 和左条带的 lstrip() 的小变体。

当数据两边有不重要的字符和符号时,使用 strip() 非常有用。这里我们先去掉右边的“!”然后去掉两边的空格。

df['Sales_ID'] = df['Sales_ID']**.str.rstrip('!').str.strip()**

Sales_ID,来源:我

祝贺您清理了 Sales_ID 列!

Sales_Branch:缺失?一点特色工程

似乎 Sales_Branch 列完全丢失了!面试官让你用 Sales_ID 一栏的提示来搞定。快速检查后,您发现销售是根据 Sales_ID 的前两个单词分配给水果的各个分支的。

我们可以用 熊猫。series . str . slice方法对字符串的关键元素进行切片。例如:'AU _ 1382578'in Sales _ ID→【AU】in Sales _ Branch

slice() 包含 3 个参数:

  • ****开始:从哪里开始,默认值为 0
  • ****停止:在哪里停止(不含)
  • ****步:多远的一步,默认值为 1
df['Sales_Branch'] = df['Sales_ID']**.str.slice(stop=2)**

销售 _ 分公司,来源:我

祝贺 Sales_Branch 专栏的特色工程!

Product_Description:包含销售产品的详细描述

大概在大多数场合,公司的系统都会产生一个长句子的交易日志。但是这些句子包含了你的面试官想要的有价值的信息。

df['Product_Description'][0]**Out: 'The Fruit, a company that sells fruits from all over the world, has branches in Australia, the United Kingdom, the United States, and Taiwan. Product: Apple Mango Banana Watermelon Orange Blueberry Banana Watermelon Kiwifruit'**

我们可以看到,虽然所有的第一句都是相同的,但我们可以将其分为两列:描述和产品。这就是 熊猫。 方法进场。

split() 包含 3 个参数:

  • pat: 默认情况下,使用空白分割什么
  • 用户可以指定他们想要多少分割
  • ****展开:当 expand=True 时,拆分被放入单独的列中
df['Product_Description']**.str.split(' Product: ', expand=True)**

来源:我

我们可以通过两种方式将 0 和 1 分配给描述和产品:

df['Description'] = df['Product_Description'].str.split(' Product: ', expand=True)[0]
df['Product'] = df['Product_Description'].str.split(' Product: ', expand=True)[1]

或者

df[['Description', 'Product']] = df['Product_Description'].str.split(': ', expand=True)

由 Unsplash 上的 Karoline Stk 拍摄的照片

现在,面试官变得挑剔了,增加了一个额外的要求:对产品列中的产品列表进行排序。

没必要感到焦虑!这可以通过首先用 split()拆分 Product 列中的值,然后在 Python 中应用排序的函数来实现。

df['Product'] = df['Product']**.str.split().apply(sorted)**

描述和产品,来源:我

祝贺您从 Product_Description 专栏中获得了信息!

Product_Count:每个销售人员的水果数量

采访者想了解他们的销售人员正在销售的各种水果。很高兴知道还可以用 熊猫。series . str . len方法获取产品列中列表的长度。

**df['Product_Count'] = df['Product']**.str.len()****

让我们来看看谁卖的水果品种最多!

**df[df['Product_Count'] == max(df['Product_Count'])]**

来源:我

卖 10 种不同水果的澳大利亚代表似乎是赢家!

恭喜你在产品计数栏中计算出了各种水果!

产品:不仅仅是产品列表

因此,在从 Product_Description 中获取产品之后,您面临着另一个挑战!面试官问你是否可以用两种方式拆分产品栏:

  1. 将列拆分为产品 1、产品 2、…
  2. 对每个产品进行一次性编码

汤姆·格伦鲍尔在 Unsplash 上的照片

1.将此列拆分为产品 n

利用 pd,我们可以轻松应对这一挑战。 系列,我们可以把它的产品列表变成pandas . core . frame . data frame

**Products = df['Product']**.apply(pd.Series)** Products**

然后,我们通过重命名列名来完成我们的工作!

**Products = Products.rename(columns=lambda x: 'Product_'+str(x))
Products**

10 行× 9 列,来源:我

2.对每个产品进行一次性编码

熊猫中的一键编码称为 熊猫。Series.str.get_dummies

******get _ dummies()只有 1 个参数:

  • sep: 要拆分的内容,默认值为' | '

我们使用拆分后的原始形式,因为我们可以使用空格来分隔它们。(填充自由以尝试使用带有循环的列表形式!)

***df['Product_Description'].str.split(': ', expand=True)[1]***

由空格分隔的产品,来源:Me

通过应用get _ dummies()*,我们从操作中得到每个水果的 10 行× 27 列(那是巨大的!).*****

***Products2 = df['Product_Description'].str.split(': ', expand=True)[1]**.str.get_dummies(' ')**
Products2***

10 行× 27 列,来源:我

在满足了这两个要求后,面试官最终决定选择选项 1 作为最终版本。我们可以将产品(选项 1)与原始数据框 df 合并,得到 10 行× 17 列的形状。

***df = **pd.concat([df, Products], axis=1)*****

仅供参考:

scikit-learn 库也提供了一个具有相同功能的“multilabel binary izer,不过那是后话了。

恭喜你将每种水果从产品栏中分离出来!

最近销售日期:年-月-日

我们几乎完成了我们的采访,最后一个任务是数据时间的职责。面试官要求您将“最近销售日期”列转换为“年-月-日”格式。这是为了进一步防止将来选择具有不同输出时间的日期的操作。

首先,我们裁剪出我们想要的日期,这可以通过两种方式实现:

***Dates = df['Recent_Sales_Date']**.str[:10]*****

或者

***Dates = df['Recent_Sales_Date']**.str.slice(stop=10)*****

Mille Sanders 在 Unsplash 上拍摄的照片

第二,简单的把它包在PD . to _ datetime()里面。

***df['Recent_Sales_Date'] = **pd.to_datetime(Dates)*****

最近 _ 销售 _ 日期,来源:我

恭喜您重新格式化了最近销售日期列中的日期时间!

收场白

面试过程正式结束!恭喜你。我希望这篇文章能给你提供我第一次技术面试的经历。虽然这次我做得不好,但这也不会是最后一次!现在,我们对熊猫的文本数据操作更有信心了。感谢大家的参与!

简单回顾一下, strip()slice()split() 方法都是处理文本数据时的有用工具:您可以选择剥离两边不相关的部分,切片可以使用的必要部分,并根据拆分标准划分数据。

这里是文章中所有代码的 Github repo!

***** [## 每当张彝伦出版的时候收到一封电子邮件。

每当张彝伦出版的时候收到一封电子邮件。或者督促他多发表!!!通过注册,您将创建一个媒体…

medium.com](https://medium.com/subscribe/@yunglinchang)

我喜欢学习数据,并思考(写下)我在实际应用中所学到的东西。如果你有更多需要讨论的,你可以通过 LinkedIn 和 Twitter 联系我。此外,请随时关注我的 Medium,以获取更多数据科学文章!

来数据科学游乐场一起玩吧!*****

熊猫与 Dask,一个超快的笔记本电脑

原文:https://towardsdatascience.com/pandas-with-dask-for-an-ultra-fast-notebook-e2621c3769f?source=collection_archive---------8-----------------------

礼貌: Pixabay

如果你进入数据世界,那么使用熊猫的需求可能会非常频繁。嗯,我们都知道一件事,熊猫是惊人的,更像是数据世界的福音。我们大多数人至少花几分钟甚至几个小时使用熊猫进行数据处理和日常分析。熊猫不需要太多的介绍,但这里有几件事你应该知道:

熊猫非常适合许多不同种类的数据:

  • 具有不同类型列的表格数据,如在 SQL 表或 Excel 电子表格中
  • 有序和无序(不一定是固定频率)时间序列数据。
  • 带有行和列标签的任意矩阵数据(同类或异类)
  • 任何其他形式的观察/统计数据集。数据根本不需要被标记就可以放入 pandas 数据结构中。

使用具有千兆字节或兆兆字节数据的熊猫更像是笔记本中的一种痛苦:d .我经常使用千兆字节的文件,笔记本就像*“等一下,让我现在冻结!”*。顺便说一下,我的系统有一些惊人的配置。使用熊猫无法处理海量数据,因此这就是我们必须开始使用 dask 的地方。在这篇文章中,我将演示如何使用 dask 和 pandas 来加速你的笔记本。在 dask 中,读取 GB 的文件只需要几秒钟。在开始演示之前,让我简单介绍一下 dask。

达斯克:

Dask 有 3 个并行集合,即数据帧、包和数组。这使得它能够存储比 RAM 更大的数据。其中的每一个都可以使用在 RAM 和硬盘之间分区的数据,也可以分布在集群中的多个节点上。Dask 数据帧是按行划分的,按索引值对行进行分组以提高效率。这些熊猫对象可能存在于磁盘或其他机器上。Dask 数据框架协调许多熊猫数据框架或沿索引排列的系列

Dask 可以利用多核 CPU 在单台机器上实现高效的并行计算,并从磁盘高效地传输数据。它可以在分布式集群上运行。Dask 还允许用户用单机调度程序替换集群,这将降低开销。这些调度程序不需要设置,可以完全在与用户会话相同的进程中运行。关于 dask 的其他一些事情:

  • 并行处理 NumPy 数组和 Pandas DataFrame 对象的能力
  • 与其他项目的集成。
  • 分布式计算
  • 更快的操作,因为它的低开销和最少的序列化
  • 在具有数千个内核的集群上弹性运行
  • 实时反馈和诊断

演示:

用于演示的完整代码可以在我的 Github repo 中找到,您可以在本文末尾找到链接。现在,让我们开始演示:

导入库:

计算运行时间和文件大小的代码:

第一个代码片段是计算我们在这里执行的操作所用的时间,例如:读取文件。在第二个片段中,我们显示了我们将在这个演示中使用的文件大小。文件大小约为 4GB。

首先,我们将看到一些东西 Dask

更擅长的事情,然后我们将跳到熊猫做得更好的事情。这将帮助您结合这两个库并执行您的分析。

关于熊猫的讨论:

读取文件—熊猫& Dask:

熊猫花了大约 5 分钟来读取一个 4gb 大小的文件。等等,大小并不代表一切,数据集中的列数和行数在时间消耗中起着重要作用。让我们看看 Dask 处理同一个文件需要多少时间。

天啊,读同一个文件只花了大约 2 毫秒,而熊猫花了大约 5 分钟。是不是太神奇了?让我们对 pandas 数据帧和 dask 数据帧执行更多的操作。

追加两个文件—熊猫& Dask:

为了执行这个操作,我们将读取另一个文件,然后将它附加到前一个文件中。

执行上述操作大约需要 9 分钟。现在让我们看看如何使用 Dask 来优化它。

好吧,好吧,你又节省了 9 分钟。现在让我们看看其他常用的熊猫。

数据分组—熊猫& Dask:

熊猫花了 6 分多钟做了一个简单的分组。让我们看看 dask 还能节省多少时间。

哇,你又节省了 6 分钟的欢呼时间。如果你使用 dask,还有许多其他的事情可以节省你更多的时间。

合并数据集—熊猫& Dask:

事情是这样的。它尝试了 30 分钟,仍然无法用熊猫合并这两个文件。看看用 dask 能不能做到。

嗯,我用 dask 只花了一秒钟就搞定了。与在推断数据类型之前读入整个文件的pandas.read_csv不同的是,dask.dataframe.read_csv只从文件的开头读入一个样本(如果使用 glob,则从第一个文件开始)。然后,在读取所有分区时,会强制使用这些推断的数据类型。

达斯克上空的熊猫:

分拣——熊猫& Dask:

我尝试根据列中的值对数据框进行排序,这花了我大约一分半钟的时间,相当不错。让我们看看 dask 如何帮助我们。

不幸的是,dask 甚至不能启动这个任务,因为 dask 没有排序功能,尽管它使用了 pandas API。熊猫万岁!

独特的&notNA——熊猫& Dask:

完成这些任务只需要大约 1 分钟。熊猫把大多数事情都做得很好,但也有一些事情做得不好。

Dask 也不支持这两件事。有许多其他的事情你会用到熊猫。

将数据帧保存到文件—熊猫& Dask:

熊猫在保存文件方面做得很好。我花了大约 3 分钟保存过滤后的文件。

Dask 没有正确保存文件。它将文件分成多个块,并将这些文件保存在一个具有上述名称的文件夹中。另一个问题是你再也不能读取这个保存的文件了。这只是浪费时间。

将 dask 数据框保存到文件的解决方案是将其转换为类似这样的 pandas 数据框,然后将 pandas 数据框保存到文件。

结论:

熊猫和达克一起使用总是最好的选择,因为一方可以很好地弥补另一方的不足。当单独使用时,我想你可能会遇到不同的问题。因此,我们得出结论,与 Dask 熊猫可以节省你很多时间和资源。

注意:

Dask 更快,因为在我们使用。计算()。虽然,这可以节省很多,很多时间,给我们更多的速度!

提示:

# Use this to make pandas run faster
pd.read_csv(filepath, engine = 'c')

如果你知道任何比 dask 更好的选择,请告诉我。

Jupyter 笔记本(使用代码):https://github . com/kunaldhariwal/Medium-12-Amazing-Pandas-NumPy-Functions

领英:https://bit.ly/2u4YPoF

我希望这有助于你增强你的知识基础:)

更多信息请关注我!

顺便说一句,你知道吗,你还可以在土星云 上免费使用 Dask 和 pandas,点击这里 ,一个云中可扩展的数据科学环境。团队可以利用强大的资源、工作、部署等进行协作。

感谢您的阅读和宝贵时间!

熊猫从零到英雄——使用熊猫的初学者教程

原文:https://towardsdatascience.com/pandas-zero-to-hero-a-beginners-tutorial-to-using-pandas-f64e57386c7c?source=collection_archive---------25-----------------------

熊猫零到英雄是一个视频教程系列,旨在教初学者友好的方式使用熊猫

在 Unsplash 上翻滚 926 拍照

在我开始无耻的宣传之前,我想先分享一下我对熊猫的发现,为什么它在数据科学界如此受欢迎,以及我开始这个视频系列的动机。

今年年初,我踏上了自学数据科学的旅程。在筛选了无限量的在线资源后,有一个平台我经常发现自己又回到了那里。这也是我开始旅程的地方,那就是卡格尔。

Kaggle 是谷歌的子公司,是一个由来自世界各地的数据科学家和机器学习实践者组成的在线社区。在这里,你可以找到迷你课程、已发布的数据集,但最重要的是,人们竞争解决各种类型的数据科学和机器学习挑战的比赛。

Kaggle 最初吸引我的是其他人从过去的比赛中分享的笔记本。作为一个从实际项目中学到很多东西的人,我很感激我可以参考这些笔记本来学习解决数据科学问题的传统方法。

最早引起我注意的事情之一是熊猫图书馆。我突然想到,在我翻阅的所有笔记本中,每个人都在使用它。

尽管当时我不知道熊猫是什么,但我能够很快掌握大多数正在使用的功能。请注意,那时我对数据科学完全陌生。这突出了这种数据分析工具的优雅性、健壮性和直观性。

熊猫是什么?

Pandas 是一个建立在 Python 编程语言之上的数据操作库。

Pandas 具有内置功能,几乎可以处理任何你想处理的数据,例如选择特定的列或行,处理缺失的数据,分组和排序,合并不同的数据框等等。

为什么你应该学习熊猫

如果您经常处理数据,或者如果您是一个认真学习数据科学的初学者,Pandas 是您的工具包中绝对应该拥有的最重要的工具之一。

任何数据科学或机器学习项目的一个关键要素是能够有效地操作和评估数据的内容。Pandas 不仅提供了一种灵活的方式来管理您的数据框架,更重要的是,它允许您清楚地分析数据本身的潜在模式。如果你想把你的数据分析技能提升到一个新的水平,这是一个强大的工具。

额外收获如果你已经熟悉了 Python 语法,你很快就能学会熊猫。但是,如果您是 Python 新手,请不要担心,学习起来一点也不难!

为什么我开始熊猫零到英雄?

我创办《熊猫零到英雄》主要有两个原因,一个是为了自己,一个是为了世界。

  1. 我想做这个教程不仅是为了加强我个人对熊猫的了解,也是为了提高我的沟通技巧和在镜头前自信地说话的能力。
  2. 我想激励和鼓励更多的人将熊猫纳入他们的数据分析工作。熊猫的投资回报率非常高,这意味着你只要学会几个基本功能,就可以立即投入工作。所有的好处与非常少的时间成本,这是一个显而易见的学习,特别是对初学者。

熊猫零到英雄的内容

受 MCU(漫威电影宇宙)中的六个无限宝石的启发,熊猫零到英雄包含六个独立的教程视频,每个视频涵盖了不同的熊猫概念。一旦掌握,它们将赋予你掌控宇宙的巨大力量——数据科学宇宙。

第 1 周:创建自己的数据框

在本教程中,我们将学习如何将 Pandas 库导入到我们的笔记本中,以及如何读取外部数据集。最常见的文件格式,至少在 Kaggle 上,被称为逗号分隔值或简称 CSV。Pandas 的功能允许你读取不同格式的数据集,包括 CSV。

除了导入和读取外部数据集,我们还将学习如何创建自己的虚拟数据框。

第 2 周:选择数据

数据框由行和列组成,行代表观察值,列代表这些观察值的要素。例如,在房价数据集中,行数对应于数据集中房屋的数量。另一方面,列将包含那些决定其最终销售价格的房屋的各种特征,如卧室数量、地块面积、与主要道路的接近程度等。

选择数据是数据科学家最基本的技能之一。它允许您仔细检查数据的子集,并对满足特定条件的特定行和列应用函数。

在本教程中,我们将学习如何使用 Pandas 中的 loc 和 iloc 函数选择数据。

第三周:功能

函数是我们在一组一个或多个输入上实现的变换或计算。换句话说,一个函数将接受一个输入,以预先指定的方式处理它,并在最后返回一个输出。

Pandas 本身已经内置了许多函数,但是如果我们想要创建自己独特的数据转换,我们可以先写出我们的函数,然后将其应用于我们的数据。

在本教程中,我们将学习一些描述性统计的基本函数,如何执行和应用 Python 函数,以及将文本变量转化为数值的编码概念。

第 4 周:分组和排序数据

分割是一种强大的方法,不仅可以将大问题分解成更小的组成部分,还可以让我们更准确地观察和分析数据中发生的趋势,从而获得更好的见解。

我们看到分段正被用于涉及问题解决的各种领域,数据科学也不例外。有许多方法可以对数据进行分组和排序。一些例子包括按客户年龄组、产品类别、地理区域等进行细分。

在本教程中,我们将学习如何根据某些特征对数据进行分组和排序。

第 5 周:处理缺失数据

缺失数据或空值是您在数据科学之旅中最常遇到的问题之一,也是一个需要正确解决以提高模型准确性的问题。

在本教程中,我们将介绍处理缺失数据的两种方法,并讨论它们之间的权衡。

最简单直接的方法是删除包含缺失数据的行或列。然而,在这样做的时候,我们会面临从数据框架中移除潜在有用信息的风险,这将对我们的模型做出准确预测的能力产生不利影响。

或者,我们可以用一些替代值来估算或替换那些缺失的数据。尽管这种方法更可取,但这一过程通常需要更多的时间、考虑和经验。

第 6 周:组合数据框架

通常,在数据科学项目中,您将使用多个数据集。因此,有时您可能需要将不同的数据框合并在一起,以使您的分析更加顺畅。

在本教程中,我们将学习 concat 和 merge,这是 Pandas 中的两个功能,允许您以灵活的方式组合数据框。

结论

这六个教程视频是速成课程,将为您提供关于如何使用熊猫图书馆的基础知识。

然而,您必须在实际的数据科学项目中尽可能多地练习使用它,以完全掌握这些视频背后的概念。换句话说,把它们当作简短的介绍性视频来帮助你开始,但是继续把它们应用到一个实际的项目设置中来最大化你的学习。

说到这里,祝你学习愉快,希望在我的下一篇文章中见到你。与此同时,请随时关注我的 YouTube 和 T2 GitHub。

感谢阅读!

PandasGUI:用图形用户界面分析 Pandas 数据帧

原文:https://towardsdatascience.com/pandasgui-analyzing-pandas-dataframes-with-a-graphical-user-interface-36f5c1357b1d?source=collection_archive---------1-----------------------

只需点击鼠标即可访问熊猫数据框

图片格式由作者| 剪贴画来源

今天 熊猫 库已经成为用 Python 进行任何探索性数据分析的事实上的工具。它的多功能性、灵活性和易用性使其成为当今许多数据科学家的首选库。熊猫图书馆也享有很好的社区支持,因此一直在积极发展和改进。由于熊猫的这种不可或缺的性质,各种各样的工具被不时地创造出来以增强它的有效性或对它进行改进。谈到熊猫,我遇到过两种特定的工具:

  • 可以用两三行代码执行基本 EDA 的工具。这些库本质上使用了熊猫的功能。例如 SweetViz 和 Pandas profiling 库。
  • 熊猫的基于 GUI 的替代品,例如 Bamboolib 。

最近,我遇到了另一个基于 GUI 的熊猫替代品,叫做 PandasGUI。令人印象深刻的一点是,它提供了绘图和重构数据框架的能力。此外,用户也可以自由地执行自定义操作。本文将尝试解释它的各种特性和功能,以及如何将它用于您的数据。

潘达斯吉

PandasGUI 顾名思义,是一个用于分析熊猫数据帧的图形用户界面。该项目仍在积极开发中,因此有时可能会发生重大变化。PandasGUI 提供了许多有用的特性,我们将在本文后面详细介绍这些特性。在此之前,让我们看看如何安装这个库并让它运行起来。

装置

有几种方法可以安装 PandasGUI:

# from PyPi
pip install pandasguior# from Github
pip install git+https://github.com/adamerose/pandasgui.git

特征

现在让我们通过一个例子来看看 PandasGUI 库的各种功能。PandasGUI 已经提供了一些示例数据集。所以我们将使用库附带的Titanic数据集。泰坦尼克号是机器学习中一个相当著名的“Hello World”数据集,其任务是创建一个模型,预测哪些乘客在泰坦尼克号沉船中幸存。

import pandas as pd
from pandasgui import show
from pandasgui.datasets import titanic
gui = show(titanic)

如果要导入数据集,可以按如下方式进行:

titanic = pd.read_csv('[https://github.com/adamerose/datasets/blob/master/titanic.csv](https://github.com/adamerose/datasets/blob/master/titanic.csv)')
gui = show(titanic)

运行以上命令后,会打开一个单独的窗口,显示上传的数据帧:

PandasGUI 中显示的泰坦尼克号数据帧|图片由作者提供

现在让我们一个接一个地看看这个工具的各种产品。

1.查看和排序数据帧和系列

您可以查看整个导入的数据帧,然后按升序或降序快速排序。注意,PandasGUI 也可以处理多类 datarfames。

按作者查看和排序数据帧和系列| Gif

2.借助查询表达式过滤数据帧

一旦浏览了数据集,您甚至可以基于一些查询表达式来过滤数据集。[**Dataframe.query()**](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.query.html)是最初由熊猫提供的用于执行过滤操作的方法。它采用字符串形式的表达式来过滤数据,对原始数据帧进行更改,然后返回过滤后的数据帧。

对于我们的数据集,假设我们要过滤以下乘客的全部数据:

  • 男性的
  • 属于 Pclass 3,并且
  • 在海难中幸存。

按作者过滤 Dataframe | Gif

3.数据编辑和复制/粘贴

这个工具的另一个很大的特点是,你可以直接编辑任何条目,甚至可以将选中的数据复制粘贴到另一个环境中,如 excel 或记事本。

作者的数据编辑和复制/粘贴| Gif

4.统计摘要

PandasGUI 还提供了整个数据集的压缩统计概览。

统计摘要|作者图片

5.交互式绘图

数据可视化是任何数据分析过程的重要组成部分,PandasGUI 提供了几个选项来快速创建一些很酷的交互式图表,如:

熊猫图形用户界面中可用的图表|作者图片

下面我们创建了一个饼图,一个条形图,甚至一个单词云。由于图表是在 plotly 中创建的,因此它们具有响应性和交互性。

互动绘图|作者 Gif

6.用旋转和熔化功能重塑数据帧

有时,需要重塑数据以获得更清晰的见解。PandasGUI 提供了两个函数— pivot 和 melts 来实现相同的功能。让我们看看如何通过这个工具透视数据。

通过透视方法重塑数据|作者 Gif

7.通过拖放导入 CSV 文件

该工具的另一个很酷的特性是,可以通过将数据帧拖动到 GUI 界面上来导入数据帧,这有时很方便。

通过拖放| Gif 按作者导入 CSV 文件

8.从 Jupyter 笔记本访问 GUI 数据框

如果您已经将数据帧直接导入 PandasGUI 界面,那么您也可以在熟悉的 juptyer 笔记本中访问该数据帧,只需几行代码。从那里,如果你愿意,你可以在笔记本上进行数据分析过程。

从 Jupyter Notebook | Gif 按作者访问 GUI 数据帧

结论

在本文中,我们看了一个基于 GUI 的工具,用于分析熊猫数据帧。这个工具有许多有趣的特性,比如过滤、排序、可视化,甚至聚合,我们在一个数据集示例中详细看到了这些特性。由于 PandasGUI 正在积极开发中,我们可能会在未来几天看到更多的功能。这样的库对于那些不太擅长编码或者正在寻找低代码环境的人来说是一个福音。无论最终目标是什么,了解另一个开源工具来添加到我们的数据科学工具包中总是有好处的。

流行病如何影响金融市场

原文:https://towardsdatascience.com/pandemics-impact-financial-markets-9a4feb6951f5?source=collection_archive---------24-----------------------

从过去的大流行中获得线索,定量分析对金融市场的影响。在 Python 中可视化和分析数据

我们正处于一个不确定的环境中,这也反映在金融市场上。你会有许多问题,例如 COVID19 将如何影响金融市场,它还会下跌多少,它将何时结束以及如何结束。在这篇文章中,我们将分析并从过去的大流行中寻找线索来回答这些问题以及我们对未来的预期。本文是根据 QuantInsti 于 2020 年 4 月 2 日就此主题举办的网络研讨会撰写的。录音和代码可从下面访问。

[## 流行病如何影响金融市场——定量分析

新冠肺炎疫情已经影响了全球股市。在本次网络研讨会中,我们将从……

blog.quantinsti.com](https://blog.quantinsti.com/pandemics-impact-financial-markets-webinar-2-april-2020/)

在我们开始深入研究对市场的影响之前,下面是我们在周围看到的或预期的新闻。

  • 企业倒闭和制造工厂关闭
  • 失业和失业率上升
  • 供应链中断
  • 日常必需品的短缺
  • 医疗系统的压力
  • 呈指数上升的感染和死亡人数
  • 还有更多……

你已经看到商店关门,制造厂关闭。没有人生产任何东西,他们没有工资支付,所以他们解雇人,因此,失业率上升。供应链出现中断,人们开始囤积包括卫生纸在内的日常必需品。这将导致短缺。与感染相关的病例数量正在上升,这给医疗保健系统造成了巨大压力。发达市场正在某种程度上应对这种前所未有的局面,但印度等发展中市场将发现很难管理医疗体系的压力。

与此同时,金融市场大幅下跌。在这种情况下,你可能会问,我们什么时候能期待一些好消息,市场什么时候会复苏,以及许多其他问题。

COVID19 对金融市场的影响

与 10 年前相比,当今市场的风险速度提高了。社交媒体驱动的新闻周期、全球供应链的相互关联性和昂贵的股票市场,使华尔街更容易受到黑天鹅的影响。

~ Seema Shah,Principal Global Investors 首席策略师

让我们从评估 COVID19 对金融市场的当前影响开始。我使用 Python 免费提供的 API 和代码创建了本文中的所有图表。所有这些代码都可以在 GitHub 上找到。

如果你是 Python 的新手,还没有使用过像 NumPy 和 Pandas 这样的金融库,那么我建议你在下面关于 Python 交易的免费互动课程中复习一下这些概念。

[## Python 交易基础免费教程

使用不同的数据结构,如列表、元组和字典,使用循环、条件语句、函数…

quantra.quantinsti.com](https://quantra.quantinsti.com/course/python-trading-basic)

让我带您看一下这段代码,它用于绘制标准普尔 500 的每日百分比变化。

代码如下所示:

SP500 每日百分比变化图

我使用了 pandas_datareader 的 get_data_yahoo 方法来获取 S&P500 的价格。

get_data_yahoo 方法有两个参数,第一个参数是股票代码,即 Yahoo Finance 中标准普尔 500 指数的“^GPSC ”,第二个参数是我想要的数据的起始日期。如果你查过,第一例冠状病毒是在 11 月 17 日确诊的。因此,我使用了相同的日期。

当我运行这段代码时,我将得到包含六列的数据集,它们是开盘价、最高价、最低价、收盘价、成交量和调整收盘价。由于我们对每日百分比变化感兴趣,我将使用 Python 的 pct_change()函数来计算它,并在 close 列上调用它。例如,如果每日百分比变化从 100 变为 102,那么我在该数据框中的值为 0.02。

如果您想用 Python 绘制这个系列,您只需传递系列的名称(在本例中为“data_pc ”)并调用函数 plot,它将绘制数据系列。这就是每日回报的样子。由于它看起来更小,我添加了一个网格,并做了一些改进,以提高其可读性。

每日百分比变化

除了 S&P500,我还绘制了原油,黄金和 TLT 的图表,这是美国市场的 20 年期国债。

我画出了它们的每日百分比变化。为了更详细地描述这些图表,蓝线是发现首例病例的日期,红线是世卫组织宣布进入公共卫生紧急状态的日期。

因此,我们可以看到 S&P500 每日价格的波动性或变化非常接近于零,我们可以看到,在世卫组织宣布紧急状态几天后,其波动性发生了急剧变化。在日常生活中,这一比例在 5%到 10%之间。此外,不仅仅是 S&P500 是美国市场的晴雨表,它也可以在原油,黄金和我们的 TLT 中看到,这是美国市场的 20 年期国债。因此,我们很容易得出结论,电晕正在使金融市场紧张不安。

观察这些图表的另一种方式是,有很多向下的运动,但也有很多向上的运动。因此,我该如何评估市场的走势呢?

累积回报

为此,我绘制了四个案例的累积收益。开始日期是报告第一例病例的前几天,最后一天是 3 月 30 日。

如你所见,红线代表原油,它似乎受到的影响最大。从顶部开始下降了将近 60%。表示标准普尔 500 的蓝线也出现了大幅下降。但如果你看看黄金,你会发现其影响不如 S&P500 和原油那么显著。

这是否意味着在这个不确定的时期,我们应该将黄金纳入我们的投资组合,作为一种合理的对冲手段?

似乎是这样,但我们不要这么快下结论。我们稍后将回到这个问题。最后但并非最不重要的是美国国债,它经历了急剧下降,但很快恢复。

水位降低

另一种方式来看这个图表是下降图。简而言之,下降衡量的是在任何特定时间段从峰值的下降。现在让我们看看图表。

例如,在 S&P500 图表中,在二月左右有一个峰值,然后下降到接近 33%。每种情况的下降值如下所示:

最大提现
原油 67.07%
SP500 33.92%
黄金 11.80%
TLT 15.72%

SP500 与原油、黄金和 TLT 的关系

提款帮助我们理解资产类别可以下降多少,但它们仍然是不同的资产类别,对吗?我们如何比较它们,或者说,它们之间的关系是什么?

为了回答这个问题,我们将创建一个散点图。散点图有助于我们理解现有工具之间的关系。

首先,我们将绘制不同仪器相对于 S&P500 的散点图。让我们看看他们看起来怎么样。

红色散点图是相对于 TLT 的 S&P500,显示了负相关关系。我们都知道,在危机时刻,会出现经济放缓,美联储和其他政府。代理机构介入后,利率就会降低。由于费率和价格之间存在反比关系,费率的降低会导致价格的上涨。因此,我们看到了 S&P500 和 TLT 之间的这种消极关系。然而,我们有一些数据点,因此在这里下结论是不明智的。

对于黄金,我们认为与 S&P500 没有关系,因为数据点分布在该图中。当谈到原油和 S&P500 时,似乎远点是负相关的,但近点是正相关的。因此,我们在这一点上不能真正下结论。

这是在不同文书之间建立联系的一种方式。基于这些关系,我们可以创建一个在流行病时期对我们有用的投资组合。

部门绩效

到目前为止,我们谈论的是整个 S&P500。但是构成指数的单个板块呢?

看待这个问题的一种方式是行业表现。我绘制了一张图表,其中考虑了市场的主要部门。

**从这张图中可以看出,制药和科技是受影响相对较小的两个行业。**在上图中,技术是这条橙色的线,你可以在最上面看到,后面是蓝色的制药线。总的来说,你可以看到所有的部分都在同一个方向,但是相对幅度,或者说下降幅度,是不同的。正如我之前所说的,制药和技术受影响相对较小。

**你可以看到粉红色的线代表能源受到的影响最大。**这是合乎逻辑的,因为我们之前已经看到原油受到的影响最大,而这又反过来影响了能源行业,因为它们两者直接相关。另一个观察是绿线,这表明金融,也下降了。其原因是,每当经济放缓时,就会有大量贷款违约,导致银行不良资产增加,最终它们的损益将受到打击。不良资产的增加使银行很难生存。印度市场的一个经典例子是 Yes bank。因此,在这场经济危机中,金融部门首当其冲。

这是否意味着我们应该忽略金融类股,转而投资科技和制药类股,我的投资组合应该是什么样的?

除此之外,我们都有如下所示的问题:

  • 什么时候会结束?
  • 会如何收场?
  • 市场会从这里进一步下跌吗?它将如何发展?
  • 我应该买黄金作为避风港吗?我的作品集应该是什么样的?
  • 它如此具有传染性,每个人都会受到它的影响吗?
  • 收益会受到怎样的影响,哪个部门会受到最大的影响?

让我们通过回顾过去的大流行和世界的发展来回答这些问题。我想在这里补充一个小小的免责声明,我没有任何水晶球可以给我一个 100%正确的答案,但我相信数据永远是得出合理结论的最佳方式。让我们现在开始吧。

过去的大流行

"那些不记得过去的人注定要重蹈覆辙。"

~乔治·桑塔亚纳

如果你认为这是一个特殊的情况,那么,你会惊讶地知道,自过去几个世纪以来,流行病一直在影响着我们。我在一个简单的表格中收集了一些数据,如下所示

来源:世界经济论坛

我用红色标出了死亡人数最多的三种流行病,绿色标出了死亡人数最少的四种。

这里出现了一个重要趋势。你能搞清楚吗?

这里实际上出现了两种趋势。一个是这些年来死亡人数显著下降。另一个趋势是期限也大幅缩短。这是因为我们有了一个更好的医疗保健系统,同时我们也付出了很大的努力来为大众寻找和部署疫苗。

但这是对过去的回顾。**冠状病毒是如何影响感染和死亡人数的?**让我们快速了解一下冠状病毒的传染性有多大

来源:世界经济论坛

这张信息图告诉了你什么?

它向我们展示了感染传播的速度。麻疹是这里 16 岁的头号杀手。这意味着一个患麻疹的人可以感染 16 个未接种疫苗的人。相比之下,冠状病毒为 2.5,这意味着一个感染冠状病毒的人平均可以影响 2.5 人。

但是为什么我们会看到病例数量呈指数增长呢?

我想用我们的投资世界做一个类比,并引起你对复利的注意。一个人在第一天就会受到影响。所以第二天 2.5 将受到影响。第三天,我们将会看到大约六个人被感染。这六个人会在 15 左右再次冲击(6*2.5)。以这种方式,受感染的人数呈指数上升。

遏制这种情况的最好方法是社会距离,这是世界上大多数政府所遵循的。

这件事会如何收场?

过去的表现是成功的最佳预测

~吉姆·西蒙斯

实际上,这里有两种情况我想谈谈。先说第一个。

场景 1:采取严格措施

严重急性呼吸综合征

在我们的历史上有一个类比,它是关于非典疫情。SARS 具有类似的性质,它于 2002 年在中国南方爆发。通过我们在周围看到的隔离、检疫和接触者追踪措施,疫情得到了控制。

在这个疫情,大约有 8500 人被感染。目前,还没有疫苗,但他们能够通过社会距离来控制这种情况,新感染的数量持平,因此,死亡人数最终减少。但是,尽管识别感染 SARS 的人很容易,但对于冠状病毒携带者来说就有点棘手了。尽管如此,我们还是可以以此为参考来理解冠状病毒对行业的影响。

来源:英国《金融时报》

在这里,我们累计计数,以及自第 100 例以来的天数。您还可以看到案例每天翻倍、第二天翻倍等等的轨迹。

例如,美国用了 24 天达到 100,000 次计数,其他国家也是如此。这里的目标是使这个指数上升曲线尽快变平。在这里,让我把你的注意力放在韩国的泥土上,他们把它弄得很平,在非典时期也做了类似的事情。现在让我们看看图表。

来源:维基百科

这是从维基百科上截取的,在这里你可以看到累积的病例以橙色线的形式,代表 8437。最初,从 4 月到 5 月,病例数呈指数增长,但由于社会距离和其他措施,增量病例数开始减少。这创造了一个“S”或我们在上面看到的逻辑曲线。死亡率遵循橙色曲线并趋于平缓。

如果我们认为 SARS 是冠状病毒的一个很好的类比,那么下面的时间表将有助于我们理解当前的情况会如何发展。

来源:疾病预防控制中心

让我们看看金融市场在 SARS 爆发期间的表现。

来源:雅虎财经和 GitHub 代码

这是我们正在使用的四种工具的相同的每日百分比变化。回想一下,原油、标准普尔 500、黄金和 20 年期美国国债。因为这是一种在中国流行的疾病,所以我们认为对金融市场的影响较小,但红线表明何时宣布这是一种可能的卫生紧急情况。你可以看到两个方向都有一些剧烈的波动,表明波动性增加了。下面的图表将使它更加清晰。

来源:雅虎财经和 GitHub 代码

你可以看到原油在此期间大幅下跌,但与冠状病毒相比,S&P500 受到的影响相对较小。黄金和 TLT 的情况也是如此。

让我们看看这一时期的提款情况。

来源:雅虎财经和 GitHub 代码

你可以看到下降相当严重。在此期间,S&P500 约为 15%,原油约为 30%。但金价又回到了 15%左右,美国国债下跌了 5%左右。我应该指出的是,由于疫情得到了很好的控制,下降幅度没有我们现在看到的那么大。

我们将尝试相关性分析,我们看到一切都与 S&P500 负相关。

来源:雅虎财经和 GitHub 代码

这不是正确的数据,因为这种流行病发生在中国。一个更好的衡量标准是将其与上证综指进行比较。但尽管如此,我们看到这段时间 S&P500 和美国国债、黄金和原油的负相关性非常高。

让我们看看危机结束后事情会如何发展。

来源:雅虎财经和 GitHub 代码

蓝色阴影区域是世卫组织宣布危机已经避免的时候。你可以看到,虽然在世卫组织宣布进入紧急状态后有相当大的跌幅,但指数实际上恢复得相当快,而且自这种情况发生以来的天数也相当短。

为简单起见,我仅采用了四种工具,您可以使用自己的本地指数进行任何您可能想要进行的相关性分析。请在评论中与我分享你的见解。

控制 SARS 的措施与控制冠状病毒的措施相似。事实上,它处理得非常好,因此它没有从中国传播出去。

我们将看到 3 月 26 日世卫组织宣布紧急状态后的结果。

来源:雅虎财经和 GitHub 代码

一定要明白,这是一个月、三个月、半年和一年的回报。你可以看到,标准普尔 500 的回报率非常强劲,在各个时间段分别为 5%、10%、15%和 25%。对其他人来说也是类似的情况。这里,CL=F 代表原油期货,GC=F 代表黄金期货,TLT 代表国债。

如果你要问哪些行业受影响最大,以及危机过后该行业的表现如何,我试图用这张图表来回答这个问题。

来源:英国《金融时报》和摩根大通

您可以看到,受影响最大的行业位于顶部,回报为正或受影响最小的行业位于底部。这张图是摩根士丹利资本国际中国板块。如你所见,受影响最大的是耐用消费品、软件、酒店、餐厅和休闲以及航空公司。受影响最小的是医疗保健、食品、饮料和烟草。深蓝色表示该行业在危机期间的表现,浅蓝色表示该行业在危机后的表现。你可以看到,食品和饮料不仅在危机期间有正回报,而且在疫情结束后也延续了这种积极的表现。这给了我们一些线索,比如快速消费品或日常必需品中的产品是我们可以寻找的,类似的医疗保健和制药公司也显示出类似的趋势。有趣的是,在疫情结束期间和之后,零售业呈现出负面趋势。

因此,如果我们认为这种情况很有可能发生,那么你就会知道哪些行业将出现健康复苏,哪些行业将需要更多时间才能复苏。

在这种情况下,我们能够通过强有力的措施控制疫情。我们现在将进入下一个场景。

场景 2:疾病广泛传播

来源:维基百科

类似的事情在过去也发生过。我们正在谈论始于第一次世界大战期间的西班牙流感,它影响了近 56%的世界人口。

另外两个是亚洲流感和香港流感,影响了大约 50 万人。为了比较,我给出了冠状病毒的数字。这些数字可能不是最近的,但它可以帮助比较现在和过去的情况。

猪流感

对于第二种情况,我们将与始于 2009 年、影响了大约 20%人口的猪流感进行类比。让我们看看这一时期的财务影响。

这是猪流感的时间表。

来源:疾病预防控制中心

现在让我们看看金融市场。

来源:雅虎财经和 GitHub 代码

蓝线是第一个病例报告的时间,红线是世卫组织宣布紧急状态的时间。

因此,你会看到与目前市场上看到的截然不同的情况,因为市场正在从 2008 年金融危机中复苏,而股票在那个特定时期被大幅低估。因此,这些运动不像我们现在看到的那样剧烈。

来源:雅虎财经和 GitHub 代码

但是尽管如此,当疫情宣布的时候,在红线之后有原油的下降。黄金和标准普尔 500 也是如此。只有 TLT 在上升,原因是美联储降低了利率以支持经济。

让我们现在检查一下提款。

来源:雅虎财经和 GitHub 代码

最大下降

原油-21.68%
SP500 -16.00%
黄金-13.56%
TLT -14.37%

所以标准普尔 500 在疫情宣布后下降了 6%。原油下跌了 18%左右,黄金下跌了 7%左右,TLT 下跌了 13%左右。然而,出现了多次波动,虽然最初并不认为它很严重,但它开始蔓延到美国的许多人。因此,我们看到许多人不是在疫情宣布时而是在后来的某个时候跌倒的。

现在让我们看看散点图告诉我们什么。

来源:雅虎财经和 GitHub 代码

在这里,你可以看到一个清晰的关系出现在资产类别中。例如,标准普尔 500 和 TLT 是负数,这意味着如果 TLT 上升,S&P 500 将下降。与黄金的关系并不明确,因此我们不能确定黄金是否是一个安全的避风港。

对于原油,我们看到两者之间的正相关关系,这意味着如果 S&P500 下跌,原油价格也会下跌。

总而言之,S&P500 与原油正相关,与 TLT 负相关,与黄金无关。

让我们看看在世卫组织说一切都好之后事情会变成怎样。

来源:雅虎财经和 GitHub 代码

正如我们之前看到的,蓝色阴影区域是在世卫组织宣布疫情结束之后。你可以看到回报相当可观。数据是申报后一年的,这些是回报。请记住,回报是从报告第一个案例的开始日期开始计算的。

从第一次约会返回

原油 73.62%
SP500 42.20%
黄金 29.89%
TLT -10.46%

因此,当一切都理清了,市场试图赶上,并进入牛市模式,一切看起来都非常正常。让我们以条形格式查看回报,以示强调。

来源:雅虎财经和 GitHub 代码

在这里,您可以看到所有仪器在时间范围内的性能。

我们来看看板块表现。

来源:雅虎财经和 GitHub 代码

有趣的是,与前一种情况不同,这里的金融部门表现相对较好,实际上处于领先地位。原因基本上是,自猪流感疫情爆发一年后,世界陷入了经济衰退,导致大量抛售,并导致金融市场被低估。科技股也是类似的情况。

能源行业在疫情期间受到了严重影响,但在形势好转后大幅反弹。这类似于我们之前看到的原油反弹。

亚洲型流感

来源:雅虎财经和 GitHub 代码

来源:雅虎财经和 GitHub 代码

我希望这能让人们对目前的形势有所了解。事实上,再做一个练习,让我们看看亚洲的流感疫情。

以下是 S&P500 的表演。

在这里,红线表示它开始在美国传播的时间。蓝色区域是在世卫组织宣布它结束之后。

同样的故事也发生在提款上,在世卫组织宣布公共紧急状态后,我们看到最高提款率为 20%。

香港流感

现在来看看香港流感告诉我们什么。

来源:雅虎财经和 GitHub 代码

红线表示世卫组织宣布紧急状态的时间,而蓝色阴影区域显示世卫组织宣布紧急状态结束后的时间。

在提款方面,我们看到最大提款率为 35%。

来源:雅虎财经和 GitHub 代码

这里的一个重要观察是,市场不喜欢不确定性。因此,当宣布紧急状态时,市场急剧下跌。但一旦我们采取了必要的措施来控制局势,一旦世卫组织宣布它是安全的,市场就会立即做出反应,反弹到危机前的水平,在某些情况下甚至超过危机前的水平。

西班牙流感

让我们看看西班牙流感给我们的启示。西班牙流感可以说发生了三波。1918 年 6 月和 7 月,然后是 1918 年 10 月至 12 月,最后是 1919 年 1 月至 3 月。我用的是道琼斯指数,S&P500 是 1927 年创建的。你可以看下面的表现。

来源:宏观趋势

你可以看到,即使在西班牙流感最严重的时期,市场也在上涨。原因是,类似于猪流感,有一个更大的事件影响了市场,这就是第一次世界大战。1918 年西班牙流感来袭时,世界正从结束的第一次世界大战中恢复过来。这就是市场上升趋势的原因。

第二次世界大战

作为题外话,下面是第二次世界大战对金融市场的影响。

来源:雅虎财经和 GitHub 代码

V 形类似于我们过去看到的图表,只是恢复的时间不同。

来源:雅虎财经和 GitHub 代码

我们知道第二次世界大战结束于 1945 年,但市场从 1942 年开始上涨。正如我之前所说,市场不喜欢不确定性。这就是为什么市场跌破,但在 1942 年,盟军已经走到一起,并开始规划一个协调的计划,以击败敌人。因此,市场考虑了这一信息,因此,一旦我们确定了计划,市场就开始复苏。这里可以看到的最大下降幅度约为 43%。

要素投资

在当前形势下,你会如何投资?一种新兴的方法是要素投资。因素的一个例子是动量,它表示如果任何东西在一年内上涨,它将继续上涨。

让我们看看 COVID19 期间一些因素的表现。

来源:范弗利特,皮姆和巴尔图森,圭多,股票风格和西班牙流感(2020 年 3 月 30 日)

从 1 月到 3 月 20 日,各种因素的月度表现如上所示。

在这里你可以看到,当其他投资者普遍持消极态度时,基于动量的因素投资却跑赢了市场。在某种程度上,即使是低波动性也跑赢了市场。但这种情况会持续下去吗?

基于目前的表格回答这个问题其实很难。让我们试着看看过去事情是如何发展的。

来源:范弗利特,皮姆和巴尔图森,圭多,股票风格和西班牙流感(2020 年 3 月 30 日)

我们可以看到,虽然动量接近市场(黑色),小盘股表现不佳。但在复苏阶段,小盘股的表现优于所有其他形式的投资。你还可以看到,在复苏阶段,动量和低波动股票的表现不如市场。

但到目前为止,我们已经看到了与流行病相关的数据。我将尝试展示 1926 年之前,或者更具体地说是 1872 年至 1918 年之间发生的市场调整数据。这些调整并不完全与大流行有关,但它们是一个非常不确定的时期,让我们看看这将如何发展。

来源:范弗利特,皮姆和巴尔图森,圭多,股票风格和西班牙流感(2020 年 3 月 30 日)

正如我们之前看到的,低波动性和基于动量的投资不会像市场那样下跌,但在复苏阶段也不会跑赢市场。相比之下,小盘股在调整阶段跌幅大于大盘,但在复苏阶段的表现优于大盘。

这什么时候会结束?

哈克特金融公司对流行病的研究表明,大多数重大病毒爆发,如 1665 年的大瘟疫和一个多世纪前的西班牙流感,都在 3 个月内发生。换句话说,那些糟糕的事件主要在 12 周内来来去去。

考虑到过去的数据显示,世卫组织宣布安全的天数已经减少,我们可能需要三到六周的时间。

猪流感:116 天
非典:101 天

然而,我怎么强调社交距离的重要性都不为过。世界各地的政府应该积极主动地施加社会距离。事实上,以下是西班牙流感在美国蔓延时美国各城市的图表。

来源:国家地理

阴影区域是实施封锁的时间,你可以看到死亡人数迅速下降。因此,社交距离对于克服这种危机是非常有效的。

如何保护你的股票重投资组合?

如果你在考虑你的投资组合,那么 TLT 是有意义的,因为它与 S&P500 负相关。你应该避开原油,因为由于当前的危机,对原油的需求可能会减弱。

注意:在采纳任何建议之前,您应该咨询财务顾问。

摘要

唷!我们经历了相当多的场景。让我们试着用表格总结一下。

来源:雅虎财经和 GitHub 代码

您可以看到,在缩减方面,COVID 排名第三,为 33%。但如果你在六个月后检查回报,它们看起来真的很有希望。这将让您对 COVID 19 后 6 个月和一年后的回报有所了解。

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指南 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

来源和参考

  1. 大英百科全书
  2. 疾控中心
  3. 世界卫生组织:世卫组织
  4. 雅虎财经
  5. 金融时报
  6. 世界经济论坛
  7. 医药网
  8. 源代码
  9. 维基百科(一个基于 wiki 技术的多语言的百科全书协作计划ˌ也是一部用不同语言写成的网络百科全书ˌ 其目标及宗旨是为全人类提供自由的百科全书)ˌ开放性的百科全书
  10. 摩根大通
  11. 霍华德·马克斯备忘录
  12. NCBI
  13. 世界经济论坛
  14. 摩根大通
  15. van Vliet,Pim 和 Baltussen,Guido,股票风格和西班牙流感(2020 年 3 月 30 日)
  16. 国家地理
  17. 熊猫数据阅读器

面板数据回归:一种强有力的时间序列建模技术

原文:https://towardsdatascience.com/panel-data-regression-a-powerful-time-series-modeling-technique-7509ce043fa8?source=collection_archive---------2-----------------------

在数据科学和机器学习问题中应用计量经济学

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

在之前的一篇文章中,我简要提到了面板数据模型;在这篇文章中,我将通过一些技术细节对此进行更深入的探讨。正如我在那篇文章中所说的,计量经济学拥有数据科学家工具箱中一些最重要的工具。它有许多用例——从测量温度变化对农业的影响到时间序列数据建模和预测。

什么是面板数据?

那么到底什么是面板数据呢?首先,让我们来看看下面的定义:

面板数据是随时间重复测量的观察的多维数据。

这是一个单行的定义,但是有很多内容需要解释。该定义隐含地描述了面板数据集的三个关键属性:

  • 特性 1:重复观察相同的对象/个人
  • 特性 2:对那些相同的个人/对象测量多个变量
  • 特性 3:观察发生在多个时间点

为了说明这些属性,下面是一个假设的(我在运行中创建的)数据集,有 4 列 4 行。

  • 数据集包含两个(假想的)美国县的 4 个观测值-克劳县和布尔县(属性 1)。
  • 对于每个县,测量了 2 个变量—安装的速度摄像头的数量和交通违规的数量(属性 2)。
  • 最后,测量发生在 2 个不同的离散时间点——2018 年和 2019 年(属性 3)。

多酷啊!

面板数据回归技术

我现在将继续描述面板数据建模技术如何回答特定的问题。假设使用上述 4 x 4 数据集,我们想要回答以下问题:

安装的测速摄像头数量对交通违章案件数量有影响吗?

如果我们运行简单的线性 OLS 回归,我们应该能够快速检查两个变量之间的关联(如果有的话):

traffic _ violation = f(speed _ camera)

然而,请记住,这不是普通的数据集,这是一个面板数据。这意味着我们可以比运行简单的 OLS 回归更有效地使用它。

怎么会?

首先,我们不应该忘记自变量还有另外两个属性——county 和 year。这意味着个体和时间维度存在差异,我们可以在更高级的模型中捕捉到这种差异,我们称之为 面板数据回归

面板数据模型(即估计量)有三种主要类型,下面简要介绍它们的公式。

a)汇集 OLS 模型

混合 OLS(普通最小二乘)模型将数据集视为任何其他横截面数据,并忽略数据具有时间和个体维度。这就是假设与普通线性回归相似的原因。

b)固定效果模型

虽然安装速度摄像头可能会对交通违规产生影响,但由于速度摄像头以外的原因(例如,高速公路巡逻率较高),每个县的交通违规情况也可能有所不同。).然而,这并没有反映在上述 OLS 模型中。固定效应模型更进了一步,它考虑了个体实体(在我们的例子中是县)之间的差异:

c)随机效应模型

在固定效应模型中,我们控制了各个县之间的差异。但是那些在个体中不变但随时间变化的变量呢?随机效应模型考虑了这些个体变化以及时间相关变化。该模型消除了变量的偏差,这些偏差是无法观察到的,并且会随着时间的推移而变化。

履行

真的只是几行代码(假设你已经完成了数据角力的另外 80%的工作!).是镇上最好的 R 库,只需三个简单的步骤就能实现你的模型:(1)输入数据;(2)将数据转换成面板数据帧;(3)实现您指定的模型。

# import package
library(plm)
# import data 
df =   read.table("../data.csv")
# convert the data frame to a data format recognizable by `plm` 
pdf = pdata.frame(df, index = c("county", "year"))
# specify and run the model
model = plm(traffic_violation~speed_camera, data = pdf, model = "random")summary(model)

最终注释

数据科学是一个不断发展的学科,来自许多学科的各种工具和技术丰富了它。计量经济学提供了传统上用于社会和经济研究的工具,但也增加了数据科学的价值。对于那些感兴趣的人来说,两本开放存取的书可以让你开始计量经济学和高级社会科学研究:

  • 计量经济学导论与 R 与
  • 带 R 的计量经济学原理。

这两本书以通俗易懂的方式描述了复杂的技术,以及 R 编程语言的应用和实现。

PAPEM-DM:迈向数据科学胜利的 7 个步骤

原文:https://towardsdatascience.com/papem-dm-7-steps-towards-a-data-science-win-f8cac4f8e02f?source=collection_archive---------76-----------------------

数据科学项目生命周期

数据科学管道的高级概述。

介绍

在这篇文章中,我将尝试分解成功的数据科学项目所涉及的步骤:从理解业务需求到维护您的数据科学团队最终产生的任何数据产品。在这个过程中,我们将讨论每个步骤的要求以及每个步骤所必需的技能和工具。

PAPEM-DM:数据科学框架

我第一次了解数据科学管道是在参加 Codeup (完全沉浸式、基于项目的 20 周数据科学和 Web 开发职业加速器)时。从那以后,我阅读了无数的文章,列举了数据科学项目中涉及的步骤,但我还没有遇到一篇包括所有这些步骤的文章。因此,这篇文章。

PAPEM-DM 是一个方便的首字母缩写词,是我自己编的,用来提醒我的步骤:计划、获取、准备、探索、建模、交付和维护。这应该从头到尾涵盖数据科学流程的所有主要步骤。如果我错过了什么重要的东西,请告诉我!哦,等等,他们都很重要…所以评论吧!LOL。

规划

在这第一步,我们必须确定需要解决的问题。大多数利益相关者和最终用户讲的是业务,而不是数据科学;通常情况下,他们问的问题要么太笼统,要么太具体,无法解决需要解决的实际问题。当开始一个新的项目时,重要的是在迷失在杂草中之前先了解事情的商业方面。

在《用数据思考的一书中,马克斯·史隆主张先回答“为什么”,再弄清楚“如何”他建议使用由背景、需求、愿景和结果组成的 CoNVO 框架。有哪些情况或术语可以更好地理解或解释问题?利用数据可以满足哪些特定需求?一旦项目达到目标,它会是什么样子?最后但同样重要的是,项目的可交付成果将如何在组织内使用,谁将拥有或维护它?

这一步不需要特别的工具,但这并不意味着它不重要。事实上,这一步非常关键,因为它可能意味着您的数据科学项目的成败。

这一步的可交付成果是对您想要完成的事情和成功的衡量标准的清晰描述。

获得物ˌ获得

这一步包括获取原始数据,您需要这些数据来洞察您所面临的问题。它要求您考虑从哪里以及如何获取数据,以及这是一个手动还是自动的过程。

您需要的工具将取决于数据源(数据将来自哪里)和您的工作环境。例如,如果数据已经存在于数据仓库中,那么获取数据可能仅仅意味着使用 SQL Alchemy 连接到您的数据仓库(如 Redshift ),并通过 Pandas dataframe 将其加载到您的 Python 环境中。另一方面,如果数据是通过电子邮件定期发送的,您可能希望使用 Fivetran 等连接器服务首先将文件加载到 Redshift 中,然后使用 Microsoft Power BI 等业务分析工具连接到 Redshift 集群。如果一个项目是一次性的特别请求,那么这个过程可能仅仅意味着检索一个平面文件(。csv,。tsv,甚至。xlsx ),然后将其直接加载到 Pandas 数据帧中,以便在 Jupyter 笔记本中进行进一步处理。另一种直接的方法是从 Salesforce 或 Zendesk 等 CRM 平台中手动提取数据。

无论是哪种情况,这一步的结果都是一个数据集,可以被您选择的武器(或工具)处理。

准备

真实世界的数据通常是杂乱的,在进行分析之前需要清理和处理。数据准备就是将我们从上一步获得的原始数据转换成一种格式,使我们能够收集见解。该步骤中涉及的一些过程通常包括处理缺失值、null 值、NaN 值和重复值。根据项目的性质,这些可能需要估算或完全放弃。还需要处理数据类型以及日期时间冲突。此外,您可能还需要将几个数据集合并到一个大规模的表或数据框架中,或者甚至将大量的列精简为几列。

同样,所需的工具将根据您的工作环境而有所不同。对于 Python,您可能使用的库是 Pandas、matplotlib 和 scikit-learn。如果您正在使用 Power BI,您很可能会使用它的 Power 查询编辑器和 DAX 公式,请记住,在连接和合并工作之前,表之间的关系也必须正确定义。如果您的组织使用 Fivetran,您可以在分析之前使用它的“转换”特性来执行一些 SQL 查询。

一旦您完成了清理和准备工作,您就可以进入下一步:探索性数据分析。

探测

根据 工程统计手册 ,探索性数据分析,简称 EDA,是一种采用多种技术进行数据分析的方法,目的是:

  • 最大限度地洞察数据集;
  • 揭开底层结构;
  • 提取重要变量;
  • 检测异常值和异常值;
  • 测试基本假设;
  • 开发简约的模型;和
  • 确定最佳因子设置。

换句话说,这一步是你开始处理数据以发现有趣的模式、异常,并发现哪些特征或变量是你最大的驱动因素。

特征工程和预处理也是这一步骤的主要组成部分。对于 Python,可以使用 Pandas、scipy、numpy、statsmodels 和可视化库,如 matplotlib、seaborn、plotly 和 bokeh。

在这一步结束时,您不仅应该有一个可以在机器学习模型中使用的格式的数据集,而且还应该回答在规划步骤中解决的一些问题。

建模

这是数据科学项目生命周期中最受欢迎的部分。在建模过程中,我们将经过清理和处理的数据用于训练和测试一个或几个机器学习算法,以便进行预测。

机器学习算法的类型包括回归,分类,聚类,异常检测,时间序列预测,以及我最喜欢的:自然语言处理或 NLP。

这一步涉及的任务有:

  1. 将数据分成训练集和测试集
  2. 确定最适合项目特定用例的机器学习模型
  3. 训练模特
  4. 基于训练集进行预测
  5. 评估训练集的结果
  6. 调整超参数
  7. 冲洗并重复
  8. 选择性能最佳的型号
  9. 基于测试集进行预测
  10. 评估测试集的结果

有太多的机器学习算法,由数据科学家根据特征(变量)和目标(我们试图预测的东西)的性质来选择使用哪一种。

交付

训练和评估一个机器学习模型很好,但迟早,你需要让其他人使用你发现或开发的东西。数据科学项目的交付成果可以像幻灯片一样简单,报告您的探索性数据分析的结果,并对后续行动提出建议。另一个是自助仪表板,其他人可以使用它来促进基于数据的管理。您可以在数据库中生成另一个可用于实时报告的表。最后但同样重要的是,您可以开发一个应用程序,使用您训练好的模型根据新的观察结果进行预测。例如,处理与客户的聊天记录以预测他们的满意度或当前情绪的机制。

这一步所需的工具将取决于项目可交付成果的类型。所需的技能可能很简单,比如在使用 AWS 或 Azure 等服务的无服务器环境中采用讲述故事的技术或成熟的管道部署。技术能力也是决定您可以交付何种类型的数据产品的一个因素。这也是为什么与数据工程团队保持良好的工作关系至关重要。事实上,在一个完美的世界里,数据科学家和数据工程师应该步调一致。

在我们今天生活的这个敏捷世界中,今天发布一个最低可行产品(MVP)比明天发布一些完美的产品更有益。

“现在发货,以后迭代。”

–查纳

维护

维护数据科学项目需要对管道中的每个组件保持警惕。它有助于从头到尾回顾和检查任何会影响项目的变更。例如,数据的形状和结构可能会改变,这将影响您的预处理脚本。确保您知道您使用的包和库的安全漏洞,并相应地更新每一个包和库,同时确保不破坏项目依赖性。此外,随着新技术的出现,寻找改进管道的机会(如自动化)。

结论

这篇文章已经很长了。概括地说,在规划和执行数据科学项目时,使用 PAPEM-DM 框架。请注意,框架中的步骤并不是相互隔离的。通常情况下,你会发现自己在以一种迭代循环的方式而不是顺序地做这些步骤。例如,您可能希望在建模后进行更多的探索,因为您在结果中发现了一些有趣的东西,并且希望深入研究。只是不要在杂草中迷失太多!

今天到此为止!

您对数据科学项目生命周期有什么样的体验?当从开发切换到生产时,这个框架会如何变化或保持不变?请留言,多多益善!

论文剖析:完形填空驱动的自我注意网络预训练:艾

原文:https://towardsdatascience.com/paper-dissection-cloze-driven-pretraining-of-self-attention-networks-a91adb2d9b18?source=collection_archive---------45-----------------------

一种用转换器预训练语言模型的新方法。

完形填空驱动的自我注意网络预训练是脸书人工智能研究所发布的一种新型语言预训练,旨在使用 transformer 模块获得改进的单词嵌入进行微调。由于这是一次论文剖析会议,如果读者需要更好地理解,我将尝试从直觉和数学两方面解释论文的主要思想。如果读者能同时打开这篇文章和报纸,并开始一起阅读,那就太好了。我将跳过摘要、介绍和相关工作部分,从第 3 部分开始。

先决条件

关于变形金刚的知识。杰伊·阿拉姆马的这篇博客和原始论文一起,对理解《变形金刚》非常有帮助。

3。双塔型号:

在这一部分,本文揭示了他们的新颖的结构,以预训练单词嵌入。在直接跳到架构之前,让我们先建立这个预训练的直觉。

现在,什么是完形填空阅读?完形填空阅读是一种教学策略,要求用户从单词库中用正确的单词填空。例如,给定一个句子,这是我的第一篇中文章,预训练的思想是预测我的,给定这是和**第一篇中文章。**有道理?如果没有,不要担心。一会儿我会展示一个示意图,让你超级清楚。

让我们来看一下双塔的类比。现在,假设这两座塔是两个黑匣子。由于单词/令牌 my 在短语之间,这是这是将前往左塔,而第一中间文章将前往右塔作为输入,以最终预测 **my。左塔或前塔从左到右工作,这意味着给定这是,它试图预测我的,右塔或后塔从右到左工作,这意味着给定文章介质第一,它试图预测我的。**句子的开头和结尾都附有 < s > 标记。由于两座塔的输入句子长度不同,需要进行屏蔽。

3.1 块状结构

图 1:完形填空预训练的模型结构。来源:原始论文

在这一节中,我将详细介绍双塔。这些塔是堆叠在一起的变压器解码器模块,如图 1 所示。绿色方块是前塔的一部分,蓝色方块是后塔的一部分。从给定的图中可以看出,给定前塔的 < s >、a 和后塔的 c、****b需要最终预测。

本文使用了一种不同的使用 CNN 编码的单词嵌入。编码的细节可以在这里找到。简而言之,给定的单词输入被分解成字符并生成字符嵌入。除此之外,还使用不同滤波器尺寸的 Conv1D 层,从而获得不同尺寸的输出。在此之后,应用最大时间池操作来获得单词的固定维度表示,将其提供给高速公路网络以获得最终的单词嵌入。这个过程如图 2 所示。

图 CNN 编码的细节。从文字输入到高速公路网是本文的相关内容。来源原文论文。

完形填空预训练使用这种 CNN 编码来生成单词嵌入。固定正弦位置编码(如 transformer 论文中所述)与 CNN 编码的单词嵌入相加,以提供单词在句子中的相对位置。为了让读者更好地理解,我准备了模型架构的扩展版本。这如图 3 所示。CNN 编码+位置编码生成单词/令牌嵌入,用作转换器模块的输入。输入嵌入在两个塔之间共享。每层前后塔的块数相同。明确一下,块 11 表示第一层的第一块,块 N3 表示第 N 层的第三块。在预训练时,如果我们想要预测第 i 个令牌/单词(例如 my ,在转发塔中,他们屏蔽了所有在 i 之后的令牌,包括第 i 个令牌。类似地,在向后的塔中,它们屏蔽了在 i 之前的所有记号,包括第 i 个记号,使得模型在预测第 i 个记号时不会得到该记号的信息。

图 3:完形填空预训练的扩展模型结构。

这里需要注意的一点是,在左边(绿色)侧,模块 11 仅从s>T21 获取输入,模块 12 同时从st获取输入,这个模块 13** 从s>获取输入,这个和**就是****

3.2 表示的组合

在本节中,我将讨论图 3 所示的联合收割机块。一旦两座塔建成,最后一层的输出将与自我关注层结合。在此之后,使用一个前馈模块,通过大小为 V (其中 V 是词汇大小)的 softmax 激活来预测正确的单词/令牌。

他们没有建议简单地馈送前向和后向塔的最后层的所有输出,而是在这样做之前使用掩蔽。屏蔽几乎与前面类似,即对于前向塔,屏蔽第 i 块之后的所有输出,包括第 i 块;对于后向塔,在预测第 i 令牌时,屏蔽第 i 块之前的所有输出,包括第 i 块。如果, FL1 ( 同图 3 中的绿色区块 N1**)BL1 ( 同图 3 中的蓝色区块 N1)**是最后一层区块 1 的输出(符号中的 L 和图 3 中的 N),则 FL1、FL2、…、FL(I-1)【T24 最终层的剩余块被屏蔽以预测第 i 个令牌,如图 3 所示。在自我关注层中, FL(i-1)BL(i+1) 被求和并串接,分别作为基模型和大模型的查询向量。基于前向和后向块的其他未屏蔽的最终层输出来创建关键字和值向量。

i 个模块的输出屏蔽在预训练期间完成,但在微调时屏蔽被移除,这表明测试结果有所改善。

4 微调

不同的过程用于不同的微调任务。

分类和回归任务

图 4 显示了单句任务的微调过程。变化是:(a)输入句子的所有记号都到每个塔。(b)移除具有 softmax 激活的前馈层。在这种情况下,语言模型的输出将是自我关注层的输出,即:**【批量大小 X 时间步长 X 关注度】。由于所有输入的句子在开头和结尾都附加了记号 < s > ,所以很容易得到这两个记号的自我注意输出向量,并且将它们连接起来产生一个向量2 * attention-dim(attention-dim = 1024****)size。**基本上,这两个令牌用于计算分类和回归任务的最终输出。如果这是一个分类问题,在级联向量的顶部,一个前馈层与 softmax 激活一起使用,以输出期望数量的类。对于回归,输出维度是 1,激活是线性的。

图 4:对单句任务进行微调的图示,其中第一个和最后一个标记的输出被提供给特定于任务的分类器(W)。最终组合层(梳状)的掩膜被移除,这导致基于所有前向和后向状态的表示

当输入是两个句子或问答对时,则在两个输入句子之间使用一个分隔符( < sep > )。所以,在自我关注层的输出连同 < s > token 向量,我们也得到了 < sep > token 的向量输出。在句子对问题中,不是仅连接 < s > 记号向量,而是连同 < s > 记号向量 < sep > 记号向量也被连接以产生 3*attention-dim 向量。现在在回归或分类问题的基础上,前馈层被用于描述单句任务。

结构化预测任务

对于命名实体识别,输入将是预先训练的语言模型的输出,但是没有仅在自我注意层的输入处的掩蔽。

无屏蔽

可以看出,在自关注层的输入处禁用掩蔽改善了测试结果。但它不建议在塔的最后一层之前禁用掩蔽。

结论

我跳过了其余部分,因为它们以非常简单易懂的方式描述了模型参数、数据集和结果。请在评论中告诉我,我是否应该将这篇文章扩展到实验设置和结果部分。

论文摘要:发现强化学习代理

原文:https://towardsdatascience.com/paper-summary-discovering-reinforcement-learning-agents-3cf9447b6ecd?source=collection_archive---------27-----------------------

通过元学习学习更新规则

Jelleke Vanooteghem 在 Unsplash 上拍摄的照片

介绍

虽然深度学习领域发展速度极快,但有可能让我们更接近人工通用智能(AGI)的独特研究很少,也很难找到。这个规则的一个例外可以在元学习领域找到。最近,元学习也被成功地应用于强化学习。Oh 等人的论文“发现强化学习代理”从 DeepMind 提供了一个新的和令人耳目一新的视角来看待元学习在强化学习中的应用。

传统上,RL 依赖手工制作的算法,如时间差异学习(TD-learning)和蒙特卡洛学习、各种政策梯度方法或其组合,如行动者-批评家模型。这些 RL 算法通常经过微调,以训练模型完成非常特定的任务,例如玩 Go 或 Dota 。一个原因是,为了稳定训练,需要调整多个超参数,例如折扣因子γ和自举参数λ。此外,非常更新的规则以及诸如值函数的预测器的选择需要努力地选择,以确保模型的良好性能。整个过程必须手动执行,并且通常是乏味和耗时的。

DeepMind 正试图通过他们的最新出版物来改变这一点。在论文中,作者提出了一种新的元学习方法,通过与一组简单的环境进行交互来发现学习目标和探索过程。他们称这种方法为习得政策梯度(LPG) 。这篇论文最吸引人的结果是,该算法能够有效地推广到更复杂的环境,这表明了纯粹通过交互来发现新的 RL 框架的潜力。

在这篇文章中,我将试着详细解释这篇论文,并在我理解有问题的地方提供额外的解释。因此,如果你想了解更多的细节,我将尽量贴近本文的结构,以便你能在原文中找到相关的部分。让我们开始吧!

元学习和早期方法

深度学习(包括深度 RL)是众所周知的极度数据饥渴。相比之下,人类可以更有效地学习新技能。例如,会骑山地车的人也可以很快学会如何骑公路车。也许他们甚至可以学习如何骑摩托车,而不需要太多额外的外部输入。元学习旨在通过“学会学习”为机器学习模型配备类似的能力,即学习训练过程,以便更快地适应新的数据分布。

在论文中,作者根据他们旨在解决的问题细分了元学习框架:

  • 仅使用几个例子将在一个或多个任务上训练的模型适应新的任务(少数镜头适应):这种变体由通用算法举例说明,例如 MAML 或爬行动物,以及 RL 特别是在 RL 的上下文中。
  • 单个任务在线改编的元学习 : 徐等人(同样来自 DeepMind)的元梯度 RL 就属于这一类。该算法在与环境交互的同时在线调整超参数,例如γ和自举参数λ**。也有可能以这种方式学习内在奖励或辅助任务。**
  • 学习新的 RL 算法:已经有多个团队在尝试通过与多个环境交互来元学习新算法。例如,进化策略梯度方法试图使用进化方法来学习策略梯度损失函数。DeepMind 的研究人员最近也表明,探索的有用知识可以作为一种奖励功能来学习。

以上所有方法都使用了价值函数的概念,并试图将其一般化。在所描述的论文中提出的框架第一次尝试学习它自己的引导机制。现在让我们来看看这是如何做到的。

已知政策梯度(LPG)

本文的主要目标是找到最佳梯度更新规则:

让我们详细解释这个公式:由η参数化的最佳更新规则使代理生命周期结束时的期望回报最大化,

据此,我们从环境 p(ε)和初始代理参数 p(θₒ).的分布中取样这意味着在训练一个代理直到它的寿命结束之后,我们想要达到最大的期望回报。

为了实现这一点,而不具体指定我们采样的环境类型,我们要求代理生成两个单独的输出:

  1. 预测的策略π(a|s)通常在策略梯度算法中,
  2. 输出在范围[0,1]内的 m 维分类预测向量 y(s)。

策略和预测向量 y(s)都被用作元网络的输入。元网络是一个反向 LSTM,在每个更新步骤产生一个关于如何更新参数π_hat 和 y_hat 的指导(见图 1)。在这一点上,我并不完全清楚为什么选择了落后的 LSTM 模式。我的理解(虽然我可能是错的)是向后的方向(从环境生存期结束到初始代理状态)对应的是代理的梯度下降优化中的向后方向。

图 1:元学习过程。来自:Oh,Junhyuk,等《发现强化学习算法》。arXiv 预印本 arXiv:2007.08794 (2020)。

元学习 LSTM 网络的输入是

其中 r_t 是时间 t 时的奖励,d_t 表示剧集终止,γ是前述的折扣因子。由于 LSTM 不明显依赖于观察和动作空间,所以它在很大程度上对环境是不变的。相反,通过训练有素的代理π的策略,观察和动作空间仅被间接考虑。

更新代理

在内部循环中,代理使用以下公式进行更新

如果您仔细观察这个公式,您会注意到期望值中的第一项与加强更新类似,只是使用了π_hat 而不是通常的期望回报 g。由于π_hat 是由元学习者生成的,因此它允许算法灵活地指定自己的“值”函数概念。

第二项最小化预测 y 和期望 y 之间的 Kullback-Leibler 散度(分布的一种距离度量形式)。y 为 LSTM 发现有用的更新规则提供了额外的信息。元学习者可能通过 y 间接影响政策。

更新元学习者

更新元学习者 LSTM 的公式如下:

这肯定需要一些解释。理想情况下,我们希望优化环境分布上的最佳梯度更新规则的公式,如上所示。正如您可能注意到的,寿命结束时的预期回报取决于带有寿命结束参数的保单的预期,而这些参数又取决于η。这种认识使我们产生了将元梯度作为政策梯度来计算的想法。上面公式中的第一项正好对应于这个梯度。

其他项是正则项。引入这些是因为元学习可能非常不稳定,特别是在训练过程的开始,y_hat 没有任何附加的语义。前两个正则项用于最大化策略和预测向量的熵。策略熵正则化是 RL 中众所周知的技术(例如参见https://arxiv.org/abs/1602.01783)。其余的术语引入了 L2 正则化。这有助于防止策略和预测更新的快速变化。

警告

如您所料,在让这种方法发挥作用之前,还有一些其他小的实现问题需要解决。

首先,在跨不同环境培训代理时,不可能对所有代理使用固定的学习率。作者通过以下事实来解释这一点:最优策略π_hat 需要根据学习率更新来缩放,以使训练稳定。此外,由于η和π_hat 在训练期间改变,我们别无选择,只能在元学习期间动态调整学习速率(值得注意的是,这仅用于训练元学习者)。在该论文中,建议使用 bandit 来分别对每个寿命的有用超参数进行采样,并根据寿命结束时的回报来更新采样分布。

此外,在补充材料中,作者指出,每当策略的熵变成 0(策略变成确定性的)时,他们就重置生存期,以防止训练崩溃。

实验

为了训练 LPG,作者为代理人设置了两个极其简单的玩具环境。其中之一是一个简单的网格世界,在环境中的特定像素处有奖励,如下图所示。第二个是延迟马尔可夫决策过程(MDP)。这只是一种描述环境的复杂方法,在这种环境中,代理人可以在某个时间点做出决策,而该决策将在稍后的某个时间点获得积极或消极的回报。每个领域使用 5 种不同的环境,捕捉诸如“延迟奖励、嘈杂奖励和长期信用分配”等问题。有关实验设置的更多详细信息,请参考文章。

图 2:来自网格世界的预测结果。来自:Oh,Junhyuk,等《发现强化学习算法》。 arXiv 预印本 arXiv:2007.08794 (2020)。

在我看来,论文中提出的两个最重要的问题是:

  • LPG 如何发现预测的有用语义?
  • 液化石油气能推广到更复杂的环境吗?

预测语义学

图 2 显示了论文中的可视化预测。左上方是一个网格世界示例,其中包含积极和消极因素,左下方是一个接近最佳的策略(白色路径)及其值(黄色=高,蓝色=低)。实验的结果显示在右边。这些是左下方策略的 y 的 30 个组成部分。这些是通过使用具有固定策略的 LPG 更新 y 获得的。查看预测,我们可以看到几乎所有的预测都与真实值有很高的相关性。它们中的一些在正奖励周围具有大的值,并且这些值被传播到邻近的像素。正如作者所指出的,这个“隐含地表明 LPG 正在要求代理人预测未来的回报,并使用这样的信息进行引导”

为了显示可视化中看到的相关性确实存在,训练了一个简单的 1 层感知器来预测各种折扣因子的 y 的真实值。虽然 y 是用 0.995 的折扣因子生成的,但训练过的感知器也可以预测低至 0.9 的折扣因子的真实值。这意味着该框架可以自动发现预测的丰富和有用的语义,即“框架几乎可以恢复各种水平上的值函数,即使这样的语义在元训练期间没有被强制执行”。 这一点很重要,因为它表明,与单值函数相比,学习到的 30 维向量确实捕获了额外的语义信息。注意,该语义信息完全由算法学习。

图 3:推广到雅达利游戏。来自:Oh,Junhyuk,等《发现强化学习算法》。arXiv 预印本 arXiv:2007.08794 (2020)。

推广到更复杂的环境

****另一个重要结果是,LPG 可以无缝地推广到更复杂的环境,如 Atari 游戏,同时仅在上述玩具环境中进行训练。如图 3 所示,LPG 可以在几乎一半的游戏中击败人类水平的性能,而无需在如此复杂的领域上进行明确的元训练。在一些游戏中,元算法甚至超过了常用的优势演员评论家(A2C)。从图中可以看出,随着 LPG 看到越来越多的训练环境,性能提升很快。可以想象,通过专门设计的训练环境,性能在未来甚至可以超过最先进的专业算法。

讨论

从实验来看,LPG 似乎能够通过与简单(或者甚至更复杂)的环境交互来在很大程度上自动发现新的 RL 算法。由于教导人类也主要依赖于创建适当的学习环境,而不是微调更新规则,这使得训练算法和训练人类更加接近。此外,该框架能够推广到比它被训练的环境更复杂的环境,潜在地开辟了一种完全基于数据的 RL 的新方法。尽管与手工制作的 RL 算法相比,新方法在性能上仍然落后,但它可以在一些 Atari 游戏以及训练环境中胜过 A2C,这表明它严格来说并不比手工制作的方法差。我们还必须考虑到这样一个事实,即这些手工制作的方法是经过多年的工作而完善的,而 LPG 只是使用数据进行训练(如果我们暂时忘记训练稳定性的问题)。

在我看来,也许最重要的一点是,这种方法可以随着计算能力和数据的增加而扩展。这意味着随着我们的计算机越来越快(这是不可避免的),液化石油气只会越来越好。使用 16 核 TPU-v2 对论文中描述的模型进行了 24 小时的训练。虽然这可能对任何无法访问谷歌庞大计算资源的人来说都是禁止的,但在几年内,任何拥有现代 PC 的人都将拥有这种计算能力。我坚信,完全基于数据的算法最终是实现更强人工智能的唯一途径。

结论

在本文中,作者首次尝试从零开始学习 RL 中的更新规则,从而避免了手动发现复杂更新规则的繁琐过程。他们的方法完全是数据驱动的,并在学习过程中引入了归纳偏差,这也是我们可能期望在人脑中发生的。该论文表明,在玩具环境中训练时,奖励预测和状态评估是自然出现的。该方法强大的泛化能力表明,有可能从与可能简单的、程序化生成的环境的交互中发现极其有效的 RL 算法。

[知识蒸馏]从神经网络中提取知识

原文:https://towardsdatascience.com/paper-summary-distilling-the-knowledge-in-a-neural-network-dc8efd9813cc?source=collection_archive---------24-----------------------

照片由 Aw 创意在 Unsplash 上拍摄

注意——YouTube 上还有一段视频解释了这篇论文

解决的问题

作者以一个非常有趣的类比开始这篇论文,以解释训练和推理的要求可能非常不同的概念。

给出的类比是幼虫和它的成虫形式,事实上两种形式对营养物的要求是完全不同的。

我们很容易理解,在训练期间,首要任务是解决手头的问题。我们最终会采用多种技术和技巧来实现目标。即学习模型参数的目标。

例如,您可以

  • 使用已被证明能解决许多不同类型问题的网络集合
  • 你可以用辍学来更好地概括
  • 增加网络的深度,
  • 使用更大的数据集等

此外,重要的是要认识到,在寻求学习的过程中,机器学习的机制是这样的,我们将探索各种路径,这些路径虽然对学习至关重要,但在推理阶段可能并不需要。换句话说,从推理的角度来看,这些额外的信息可能被认为是多余的。

这就把我们带到了推理的需求上,除了准确性,运行时性能,也就是预测的速度也起着重要的作用。

如果您的产品因为速度慢而无法使用,那么无论它有多精确,都没有关系。在大多数情况下,可用性战胜了准确性!

本文旨在解决如何使用具有较少参数的网络架构运行精确模型而不牺牲太多精度的挑战。

现有技术及其局限性

这不是第一次讨论这个问题。Rich Caruana 等人在 2006 年发表的一篇题为“模型压缩”的论文中阐述了使用繁琐模型知识训练简单网络的概念。

繁琐模型是具有大量参数的模型或者是模型的集合,并且通常难以在具有较少计算资源的设备上设置和运行。

在本文中,Hinton 提到了模型压缩,以证明他们可以从繁琐的模型中提取信息,并将其提供给更简单的模型。

在模型压缩文件中,使用的技术是使用 RMSE 最小化 logits 空间中的距离。本文认为,他们建立在这一见解,并提出了一个更普遍的解决方案;换句话说,Caruana 等人的模型压缩技术是 Hinton 等人提出的一个特例。

理解关键见解所需的背景知识

要欣赏这篇论文的关键见解,你应该有良好的直觉以及对 softmax 激活功能的数学理解!

这里我展示了一个典型的分类网络,在最后一个输出层有 3 个神经元。这意味着我们有 3 个类。典型分类问题中使用的激活函数是 softmax 函数(在最后一层)。对于我们的讨论,在隐藏层中使用什么激活函数并不重要。

来源—文章的作者

以上动画展示了 softmax 激活公式,即

q_i = exp(z_i) / sum(exp(z_j)where j = 1 to 3
where q_i corresponds to the value of neuron i in the last layerThus the numerator corresponds to the exponentiated value of logit provided by a neuron whereas the denominator is the sum of all the logits in the exponential space.

但是我们为什么要找 softmax?这可以通过把这个问题分成两个子问题来回答

  • 为什么我们要取幂(分子部分)?
  • 我们为什么要归一化(分母部分)?

这两个问题的答案是,我们需要一个概率分布作为网络的输出。

现在任何概率分布都必须考虑两个重要的性质:

  • 分布中的所有条目都应该是正数
  • 所有条目的总和应为 1

指数函数具有将负实数转化为正实数的魔力,因此这满足了我们的第一个要求。接下来,归一化(即每个条目除以所有条目的总和)使其成为分布。

但是现在你可能想知道为什么我们需要概率分布作为输出?

在分类问题中,你使用基本事实标签作为独热编码向量。一个独热编码向量只不过是一个概率分布,其中只有一个条目得到所有的概率。因此,任务(目标)是将该基础真实概率分布与预测的概率分布进行比较。这就是为什么我们希望我们的输出是全能的 softmax 激活函数提供给我们的概率分布。这两种概率分布之间的比较是使用交叉熵损失函数来完成的。

关键见解

Softmax 适用于交叉熵损失,但它有一个问题,即在赋予最可能的类重要性的过程中,它会将其余的类推向非常小的值。

该论文从手数字分类中选取了一个例子,其中它强调了这样一种情况,即 2 的例子图像可能比 7 的例子图像更接近或相似于 3 的例子图像。

这些例子有多接近或相似对于理解网络实际学到了什么非常重要!

这里的关键见解是,softmax 函数倾向于隐藏其他类之间的这种相对相似性,并且这种信息(如果可用的话)可以在训练提取的网络中发挥至关重要的作用。

第二个关键的见解是关于如何突出类的例子之间的相对相似性,同时保持在 softmax 的领域中。

作者认为,如果在将 logitss 的值传递给指数函数之前,我们使 logit 的值(即最后一层神经元的输出)更低,那么我们将获得更平滑的分布。

这里的“更平滑”意味着与常规的 softmax 不同,没有对应于一个条目的大尖峰。

为了使逻辑的输出更低,你现在需要一个数来除它们。这个数字有一个叫做 T 的符号,作者称之为温度。温度越高,分布越平稳。

他们修改了 softmax 函数,如下所示

q_i = exp(z_i/T) / sum(exp(z_j/T)

这里的类比是蒸馏,你用温度蒸馏杂质。然而,T 的值非常重要,你必须通过实验才能找到。这就是为什么它是一个超参数。

下面的代码片段展示了不同的 T 值对 softmax 函数输出的影响

如您所见,温度(T)越高,获得的分布越平滑。T=1 的值对应于常规的 softmax 行为。

它是如何工作的?

首先,让我在这里介绍一些新的术语。

教师模型。 原始的(繁琐的)模型被称为教师模型,因为我们正在从中提取知识。

学生模型。参数较少的新模型被称为学生模型,因为我们将信息提取到其中。

软标签。 使用温度大于 1 (T > 1)的 softmax 的教师模型的输出。

软预测。 使用温度大于 1 (T > 1)的 softmax 的学生模型的输出。

艰难的预言。 当常规 softmax 用于学生模式时

硬标签。

下图说明了学生培训流程的设置。

来源—https://nerv anasystems . github . io/distiller/knowledge _ distillation . html

你最终会有两个损失项。第一个损失项使用软标签(来自教师)&软预测(来自学生),第二个损失项使用**硬预测(来自学生)和硬标签。**你可以随时配置这两项的贡献。

作者对 MNIST 和语音识别问题进行了实验,取得了很好的结果。

Android 语音识别论文的结果

各种链接和详细信息

论文有开源实现吗?

Github 上有多种实现,实现起来非常简单。这里有一个链接,链接到一个实施多个 KD 损失的存储库

【https://github.com/karanchahal/distiller

这篇论文是在一次会议上发表的吗?

是的。这篇论文在 NIPS 2014 上被接受,有超过 3000 次引用

论文链接—https://arxiv.org/abs/1412.6550

有解释论文的视频吗?

是的。我为这篇论文制作了 youtube 视频。

我的观点和建议

  • 这是启动知识蒸馏研究领域的基础论文。
  • 这篇论文写得很好,如果你对 softmax 函数的数学性质有很好的直觉和理解,那么温度的概念将是有意义的。这就是为什么我在这篇文章中花了很大篇幅解释 softmax 在分类网络中的重要性
  • 该技术(即更平滑的 softmax)仍在使用,并且通常根据不同问题和架构的要求由其他方法补充。

作为这篇文章的后续,我会写更多关于知识蒸馏的论文摘要。

希望你喜欢这个摘要,我可能误解/曲解了论文的某些部分,因此,如果有的话,错误是我的,而不是原论文作者的。

论文摘要与实施:通用音频表征的对比学习。

原文:https://towardsdatascience.com/paper-summary-implementation-contrastive-learning-of-general-purpose-audio-representations-f4e3cc06fcf7?source=collection_archive---------25-----------------------

PyTorch 实施的 COLA 培训计划。

赫拉尔·莫夫西斯扬在 Unsplash 上拍摄的照片

这篇文章是一个简短的总结和实施以下文章的步骤:

  • 通用音频表示的学习

本文的目的是使用区分性预训练来学习自我监督的通用音频表示。作者训练了一个 2D CNN EfficientNet-B0 来将梅尔频谱图转换成 1D-512 向量。这些表征然后被转移到其他任务,如说话人识别或鸟鸣检测。

DPT 背后的基本思想是定义一个锚元素、一个积极元素和一个或多个干扰元素。然后训练一个模型来匹配锚和正面的例子。

DPT —作者提供的图像

使用 DPT 的一种这样的方式是使用三元组损失以及余弦相似性度量来训练模型,例如余弦(F(P),F(A))比余弦(F(D),F(A))高得多。这将使锚的潜在空间中的表征更接近于积极的例子,而不是干扰物。上面链接的论文的作者使用这种方法作为基线来表明他们的方法 COLA 效果更好。

可乐

这种方法适用于音频领域。对于每个音频剪辑,作者挑选一个片段作为锚,另一个片段作为正例,对于这些样本中的每一个(锚,正),他们挑选训练批次中的其他样本作为干扰物。这是一个好主意,原因有二:

  • 有多个干扰物,这使得训练任务更加困难,迫使模型学习更有意义的表示来解决它。
  • 干扰项从批次中的其他样本中重用,这降低了生成它们的 IO、计算和内存成本。

COLA 还使用双线性相似度,这是直接从数据中学习的。作者表明双线性相似性比余弦好得多,相比之下,在下游任务上给出了额外的 7% 平均准确度。

在计算锚和其他例子之间的相似性之后,相似性值被用于交叉熵损失,该损失测量模型在干扰物中识别正面例子的能力(论文中的等式 2)。

可乐评价

线性模型评估

COLA 用于在 AudioSet 上训练 EfficientNet-B0,AudioSet 是一个数据集,包含来自 YouTube 的大约 100 万个音频剪辑。由该模型生成的特征向量然后被用于在广泛的下游任务上训练线性分类器。模型学习的表示越好,当用作执行监督任务的线性模型的输入时,其性能就越好。作者发现,在下游任务中,COLA 比其他方法(如三重损失)多了 20%的平均准确率(论文的表 2)

微调评估

测试这种方法的另一种方法是在下游任务中微调模型。这使得作者可以将使用 COLA 预先训练的模型与从头开始训练的模型进行比较。他们的结果显示,预训练的模型比从零开始训练的模型平均高出大约 1.2%

PyTorch 实现

这种方法很容易在 PyTorch Lightning 中实现。
编码器可以定义为:

**class** Encoder(torch.nn.Module):**def** __init__(self, drop_connect_rate=0.1):super(Encoder, self).__init__()self.cnn1 = torch.nn.Conv2d(1, 3, kernel_size=3)self.efficientnet = EfficientNet.from_name(**"efficientnet-b0"**, include_top=**False**, drop_connect_rate=drop_connect_rate)**def** forward(self, x):x = x.unsqueeze(1)x = self.cnn1(x)x = self.efficientnet(x)y = x.squeeze(3).squeeze(2)**return** y

然后可乐训练可以定义为:

**class** Cola(pl.LightningModule):**def** __init__(self, p=0.1):super().__init__()self.save_hyperparameters()self.p = pself.do = torch.nn.Dropout(p=self.p)self.encoder = Encoder(drop_connect_rate=p)self.g = torch.nn.Linear(1280, 512)self.layer_norm = torch.nn.LayerNorm(normalized_shape=512)self.linear = torch.nn.Linear(512, 512, bias=**False**)**def** forward(self, x):x1, x2 = xx1 = self.do(self.encoder(x1))x1 = self.do(self.g(x1))x1 = self.do(torch.tanh(self.layer_norm(x1)))x2 = self.do(self.encoder(x2))x2 = self.do(self.g(x2))x2 = self.do(torch.tanh(self.layer_norm(x2)))x1 = self.linear(x1)**return** x1, x2**def** training_step(self, x, batch_idx):x1, x2 = self(x)y = torch.arange(x1.size(0), device=x1.device)y_hat = torch.mm(x1, x2.t())loss = F.cross_entropy(y_hat, y)_, predicted = torch.max(y_hat, 1)acc = (predicted == y).double().mean()self.log(**"train_loss"**, loss)self.log(**"train_acc"**, acc)**return** loss

我没有计算资源来复制论文中的实验,所以我试着在小得多的规模上做类似的事情。我在 FMA 大号(没有标签)上使用可乐预训练了一个模型几个时代,然后微调了应用于 FMA 小号的音乐流派检测。

FMA·斯莫尔的结果如下:

  • 随机猜测:12.5%
  • 从零开始培训:51.1%
  • 使用可乐预先训练: 54.3%

结论

论文通用音频表示的学习介绍了 COLA 预训练方法,该方法实现了一些伟大的想法,使自我监督训练更加有效,如使用批量样本作为干扰物和双线性相似性度量。这种方法可用于提高下游监督音频任务的性能。

代码:https://github.com/CVxTz/COLA_pytorch

纸周刊:没有数据的图像重建

原文:https://towardsdatascience.com/paper-tuesday-image-reconstruction-without-data-c2acdba1aa53?source=collection_archive---------29-----------------------

每周二,我都会强调我在研究或工作中遇到的一篇有趣的论文。希望我的评论能帮助你在 2 分钟内获得论文中最多汁的部分!

基本思想

图像重建是一项具有挑战性的学习任务,因为没有人知道原始图像是什么样子的。因此,似乎唯一实用且合乎逻辑的方法是开发关于图像的一些先验知识,并挑选具有最大概率(最大先验估计)的重建。例如,我们希望在 MNIST 数据集上训练的模型能够开发一些关于手写数字的先验知识,可以用来对模糊的数字进行降噪。

我偶然看到了这篇名为 Deep Image Prior 的论文,该论文由 Ulynov、Veldadi 和 Lempitsky 于 2017 年发表。下面是链接:https://sites . skol tech . ru/app/data/uploads/sites/25/2018/04/deep _ image _ prior . pdf

研究人员发现了深度 CNN 的一个有趣特性——随机初始化的网络比纯噪声更快地拟合自然图像。换句话说,CNN 对自然图像有天然的“优先”偏好,可以利用这种偏好在没有任何数据的情况下去除图像中的伪影!

来自的论文

为了对图像去噪(去除水印、去除修补等),随机初始化 CNN 并将图像馈送到模型中(输入=图像,输出=图像,就像自动编码器一样)。不出所料,模型逐渐实现零训练损失(参数> >图像中的像素)。然而,当适当地提前停止训练时,网络产生去噪图像。

培训目标,来自论文

结果

图像重建可以采取多种形式——去噪、修复恢复、超分辨率等。研究人员证明,神经网络架构在免训练图像重建中起着重要作用

摘自论文

当选择合适的网络架构时,DIP 会产生惊人的重建性能,与监督模型相当,甚至超过监督模型:

来自的论文

来自的论文

一些想法

DIP 是过度参数化(权重> >数据)的力量被完全低估的另一个证明。在我的 ML 课上,我的教授警告我们不要在“小”数据集上使用巨型模型,因为可能会过度拟合。然而,超参数化网络有许多有趣的特性可以利用!如果我们可以用一个未训练的模型对图像去噪,谁知道一个有无数参数的训练有素的模型能做什么?

带代码的论文+ arXiv =可重复、有组织的研究

原文:https://towardsdatascience.com/papers-with-code-arxiv-reproducible-organized-research-f5404eb6a22e?source=collection_archive---------44-----------------------

通过联合合作,《论文与代码》现在为 arXiv 数据库中的文章提供分类和代码参考

在有代码的纸上轻松浏览最先进的机器学习代码

摘要

数百万篇科学文章通过 arXiv 公开分享,这是一个康乃尔支持的网站,专注于开放研究。代码为的【T4 论文】网站上有学术论文,这些论文也共享它们的支持软件,因此实验可以被忠实地复制。通过联合合作,《论文与代码》现在为 arXiv 数据库中的文章提供分类和代码参考。

arXiv 发布研究成果

我们都喜欢 arXiv。尽管这里或那里有些怪癖,前提是梦幻般的。该网站提供了物理学、数学、计算机科学、定量生物学、定量金融学、统计学、电子工程和系统科学以及经济学的开放式档案。截至 2020 年 10 月,该网站已发布超过 170 万篇文章。任何人都可以在任何时候免费获得这些文章。这使得知识能够以前几代人闻所未闻的速度被共享,同时仍然保持作者归属以用于学分分配目的。

以前,新的研究进展主要通过学术期刊传播,这些期刊是由人准备的,很可能不是免费的。虽然这个过程实现了信息的组织和共享,但是它是有偏见的,并且是排他的。由于准备期刊的工作人员的集体偏见,这个过程是有偏见的,接受一些,拒绝另一些。当然,这可能比它不工作更经常;然而,我相信它远非完美。此外,该过程具有排他性,因为它为获取信息贴上了价格标签。是的,世界在交换有价值的物品。这并不意味着价值必须是货币,也不意味着货币必须直接来自最终消费者。

arXiv 的发展有助于世界上更自由的信息流动。有了这个网站,突破性的研究现在可以以互联网电缆传输的速度向全世界传播。此外,由于网站的开放性,任何人都可以使用 arXiv API 以编程方式阅读文章。一旦你有了一个 API。有一个数据集。一旦你有了一个数据集,你就有可能得到漂亮的可视化效果,比如这个。

Paperscape 的 arXiv 文章交互可视化的高级视图。

论文与代码分发研究成果的复制

arXiv 单独支持开放研究共享这一事实对全球研究社区来说是件好事。然而,现在科学领域的绝大多数新研究都有软件支持研究结果。未能提供该软件相当于未能提供验证研究所需的所有资产。在一个以信息为中心的世界里,大多数可用的数据都是在过去几年里创建的,使用软件独立证明研究结果有效的能力变得越来越重要。你可以读一篇论文并立即知道它的有效性的日子已经一去不复返了。随机优化算法和不同的数据源需要提供软件和数据,以便充分验证现代研究。

一些排名最高的知识库都是关于论文和代码的。

PwC(papers with Code)是一个组织访问技术论文的网站,该网站还提供用于创建论文结果的软件,在过去几年中发展迅速。随着可公开获得的数据集的增加,现代研究已经开始向完全透明和可信的方向靠拢。普华永道也一直在改进自己的网站。通过按照任务(例如,对象检测、情感分析等)或者按照方法(例如,注意力、卷积)进行浏览,可以容易地浏览现有技术。此外,如下所示,普华永道还使用从论文中收集的数据来跟踪软件框架和代码可用性如何随时间变化的趋势。

这项服务使普通用户能够享受前所未有的机器学习艺术。想看看与新冠肺炎有关的一些最好的模型吗?文字嵌入、图像生成或语音识别怎么样?一切触手可及。

基于时间的框架使用和论文代码可用性趋势,由代码为的论文管理。

普华永道 arXiv 使现代科学民主化

最大的成果是通过协作产生的,这两个网站也不例外。普华永道与 arXiv 合作,直接连接到他们的网站,为读者提供所有共享软件实现的链接。不再需要点击进入论文并搜索脚注和参考文献,希望神奇的“GitHub”关键字以其所有的威严出现。虽然看起来是一个微小的变化,但这种整合越来越鼓励作者在提交材料时提供这些额外的实验细节,以便读者可以更好地验证这些发现。我想任何被训练来预测论文价值的模型都会对 has_code 特性赋予很高的权重!

带代码论文链接的 EfficientNet arXiv 页面预览。

PwC 和 arXiv 之间的集成还提供了基于论文标题和摘要的论文自动分类。现在,作者将可以选择采用自动建议的论文类别,以便更好地组织内容和增加读者范围。延续开放存取的精神,他们已经公开了模型库就在这里。多棒啊。这个模型的前一个版本不可用,这导致了对其内部工作方式的许多困惑。这个问题现在已经解决了。

结论

由于现代技术研究的统计性质,研究结果现在需要软件和数据实验细节以及白皮书文档进行验证。信息生产的惊人速度也需要开放存取和自动化组织。arXiv 和有 Code 网站的报纸已经在这些领域取得了很大进展,从混乱中带来了秩序。在最近的一次合作中,我们现在可以享受这些服务之间的集成,以及它们的数据组合所带来的好处。整体绝对大于部分之和。

链接

  • arXiv
  • arXiv API
  • 普华永道 arXiv 分类器
  • 编号为的文件
  • 纸景
  • 来自普华永道的 Robert Stojnic 的公告

不断学习

[## Hello Danfo:用于 Javascript 的熊猫,来自 Tensorflow

Tensorflow.js 刚刚获得了更多端到端

towardsdatascience.com](/hello-danfo-pandas-for-javascript-from-tensorflow-3d1d0ea3f3be) [## 亚马逊想让你免费成为一名人工智能从业者

这家科技巨头计划通过公开其长期的内部材料来提高 ML 的熟练度

towardsdatascience.com](/amazon-wants-to-make-you-an-ml-practitioner-for-free-552c46cea9ba) [## Deepnote 将成为 Jupyter 黑仔

旧金山的一个小团队 DeepNote 希望在你的数据科学工作流程中取代 Jupyter。

towardsdatascience.com](/deepnote-sets-course-to-become-the-jupyter-killer-d0cb6e3ca011)

保持最新状态

这一个就到此为止。然而,在学术界和工业界,事情发生得很快!用 LifeWithData 博客、Medium上的文章和我的 Twitter 让自己保持最新状态。

原载于 2020 年 10 月 13 日 https://www.lifewithdata.org**的

并行计算—利用 GPU 计算升级您的数据科学

原文:https://towardsdatascience.com/parallel-computing-upgrade-your-data-science-with-a-gpu-bba1cc007c24?source=collection_archive---------18-----------------------

GPU 如何加速数据科学工作流的研究

<本文的代码可以在这里找到>

照片由 Pixabay 在像素上拍摄

GPU 比 CPU 快吗?这是一个非常复杂的问题,但简单的回答是不,不总是这样。事实上,对于大多数通用计算,CPU 的性能要比 GPU 好得多。这是因为 CPU 设计的处理器内核数量比 GPU 上的处理器内核数量少,但时钟速度比 GPU 上的处理器内核速度高,这使得它们能够非常快速地完成一系列任务。另一方面,GPU 有更多的内核,并被设计用于不同的目的。最初,GPU 的设计初衷是加速图形渲染的性能。这是通过允许 CPU 卸载繁重的计算并释放处理能力来实现的。GPU 比 CPU 更快地渲染图像,因为它的并行处理架构,这允许它同时跨数据流执行多个计算。CPU 是操作的大脑,负责向系统的其他部分发出指令,包括 GPU。如今,在额外软件的帮助下,GPU 的能力已经扩展到显著减少完成数据科学不同阶段所需的某些类型的计算所需的时间。需要强调的是,GPU 不会取代 CPU,而是作为一个协处理器来加速科学和工程计算。

CPU 和 GPU 处理的比较:

GPU 与 CPU

如果你想看有趣的插图,这里有一个来自 2009 年的 视频

面向数据科学的 GPU 并行处理

在过去几年 CPU 性能增长放缓的时候,GPU 提供了显著的速度提升(可悲的是打破了摩尔定律**)。因此,预计未来几年对 GPU 计算的采用将会增加。这个特性在数据科学领域非常重要,它涉及到高效处理非常大的数据集(以矩阵/向量的形式)。 SIMD 设计,或单指令/多数据,意味着 GPU 计算可以用一条指令处理多个数据,就像矩阵乘法一样。例如,深度学习可以利用并行计算来减少训练周期中花费的时间,因为许多卷积运算都是重复的。事实上,数据科学工作流程中的许多步骤都可以通过 GPU 来处理(例如,数据预处理、特征工程和可视化),但它们确实需要额外的功能来实现。由于传统的计算机编程不是为并行处理而写的,它们需要被转换成支持 GPU 的**。GPU 制造商非常热衷于为开发者提供软件支持以加速采用。****

量化收益

为了说明 GPU 计算对深度学习的影响,我在有和没有 GPU 的情况下重新训练了 CIFAR-10 对象识别模型(来自 TensorFlow)。CIFAR-10 CNN 模型通常用于基准测试。它通过 14 层 CNN 模型用 60,000 张 32x32 的彩色图像进行训练,以给出计算强度的一些观点。因为我主要关注的是计算速度,所以我的比较指标是每秒个示例个总训练时间**。结果显示,使用 GPU 进行训练时,性能提高了 27 倍。**

使用英伟达 RTX 2080 Ti GPU (CUDA 10.0)训练的 CIFAR-10

GPU 实现了非常高的吞吐量,大大减少了训练时间。这直接转化为在时间和精力方面更低的成本。节省的时间意味着在模型开发周期中有更多的优化迭代(即模型选择特征调整**)。**

但是还有更多——云上的 GPU

GPU 云计算已经可以在微软 Azure、AWS、Google Cloud on-demand 等主流云平台上使用。尽管它并不总是和最先进的 GPU 工作站一样快。它提供了可访问性和便利性,无需投资昂贵的硬件和维护。

摘要

GPU 在数据科学领域发挥着至关重要的作用。由于其并行架构的性质,他们可以同时对数据流快速执行计算,解决了人工智能和机器学习最棘手的挑战之一。现在是时候熟悉 GPU 计算了——通过云或者在你的本地机器上。

平行坐标图

原文:https://towardsdatascience.com/parallel-coordinates-plots-6fcfa066dcb3?source=collection_archive---------26-----------------------

为什么&如何,用类比讲故事

图片来自 Unsplash 的 Mitchell Luo

又名:平行坐标、平行坐标图、平行图、剖面图

为什么:平行坐标图(PCP)是一种可视化技术,用于分析多元数值数据。它允许数据分析师一起比较许多量化变量,寻找它们之间的模式关系。当这些变量具有不同的量值(不同的标度)和不同的测量单位时,它们适用于同时比较多个数值变量。其思想是在多维数据集中发现模式、相似性、聚类以及积极、消极或无特定关系。

第一个 PCP 出版于 1885 年(#1),但它的流行是在一个世纪后通过 Inselberg (#2)的工作。它们被广泛使用,特别是在学术论文中,以克服与高维数据可视化相关的挑战。PCP 的 n 维能力使复杂的关系能够简单地绘制出来(#3)。

如何:这种表示法并没有显示经典的笛卡尔坐标平面,而是给每个数值变量赋予了自己的轴。如下图所示,所有轴平行,垂直,等距放置。数据集的每个数据元素通过连接的线段表示,从一组连接的点中导出,每个轴上一个点。我们最终得到一组线条,每一行都是每个数据记录的多轴表示。一般来说,许多平行线表示正相关,而许多交叉线(X 形状)表示负相关。

图 1:平行坐标图的示意图。该图形是用 Matplotlib 开发的。

我们的示例数据集有四个数值变量和与三个不同类相关的六条记录。所以我们得到四个平行的轴和六条线(图 1)。每条线都是从四个相连的点(每个轴上一个点)派生出来的。每一类都用一种特定的颜色来代表。我们正在寻找四个数字变量和不同类别之间的模式或关系。显然,我们有一个严重的问题:变量 4 与变量 1 和变量 3 之间的不同数量级不允许我们发现这些可能的模式。

为了解决这个问题,在绘制数据之前,我们必须执行数据标准化任务。请记住,原始数据不仅可能有不同的数量级,而且可能有不同的测量单位。标准化(缩放)将原始数据转换为新的尺度,使我们能够比较最初非常不同的量值。

有几种缩放技术。通常的做法,虽然不是最稳健的,是在其最小值和最大值之间缩放每个轴。在此过程中,最小值设置为 0,最大值设置为 1(或 100%),中间的所有其他值也相应地进行转换。例如,使用此程序进行缩放后,您可以用一个 PCP 比较两个数值变量,其中一个变量最初在 0-10 范围内,另一个在 100 和 10000 之间。其他缩放技术使用平均值和标准偏差、中值或其他统计数据将原始数值转换为通用的比例。

图 2:缩放和重新排序的平行坐标图。该图形是用 Matplotlib 开发的。

图 2 使用与图 1 相同的数据,但是每个轴在 0 和 1 之间缩放。我们进行了一些重新排序(如下所述),直到我们注意到标签 1 和标签 2 共享某种积极的关系,而标签 3 显示了相反的模式。

除了缩放之外,为了发现变量之间的模式或关系,通常在 PCP 中使用三种其他技术:着色;重新排序;刷牙。

着色意味着用特定的颜色突出显示一条或一组线条,以便在视觉上将它们与其他线条区分开来。例如,当您必须将一种特定产品与列表中的其他产品进行比较时。

重新排序是改变垂直轴的顺序。其背后的原因是相邻变量之间的关系比不相邻变量之间的关系更容易可视化。然后,你可能不会发现某种模式或关系,仅仅因为变量彼此不相邻。此外,您可以通过改变一些轴的顺序并最小化它们之间的交叉数量来减少 PCP 的混乱。现代可视化工具允许我们沿着图拖动轴,以便于重新排序。一个聪明的分析师总是尝试重新排序,直到他增强了情节的可读性,并从显示中获得尽可能多的信息。

是一种通过应用刷子选择单个数据点的技术,用于高亮显示数据子集。选定的线条会被强调,而其他线条会被淡化。画笔就像一个过滤器,可以减少线条的数量,最大限度地减少混乱,并显示数据集中的模式。在 PCP 上刷是强制性的,以避免在分析大型数据集时过度绘制和遮挡。

下图清楚地显示了刷涂技术的效用:上图(a)显示了 PCP 过度绘制的数据;下图(b)显示了应用了画笔的同一个 PCP。原始数据集对应于由专门从事呼叫中心数据收集和分析的初创公司记录的电信行业(#3)。该数据集包含 500 万条与呼叫中心的客户交互(电话)相关的记录。有九个数值变量,每个变量在 PCP 中都有相应的轴。这种梳理让该公司能够识别那些无法长时间通话来解决任何问题的呼叫者,并为电信专家提供以前未观察到的模式。很明显,在最初过度绘制的五氯苯酚中无法观察到该模式。

图 3: a)刷牙前的五氯苯酚;b)刷牙后的 PCP,来源(#3)。

警告

对于非技术人员来说,平行坐标图通常难以理解。无法避免典型的线路混乱;

尽量不要同时显示多个数值变量。屏幕中超过十二个轴及其相应的线条(即使有刷)可能会使观众感到困惑;

这种显示的一个缺点是缩放后,我们会丢失每个变量的原始值。

PCP 不适用于分类数据。请记住,分类变量,也称为定性变量,通常采用有限数量的互斥类别或组的值。这些值可以是数字,但不代表数量,而是相互排斥的组(即婚姻状况:1-从未结婚;2-已婚;3-离异;4-丧偶)。您必须使用带有分类变量的平行集图

雷达图(蜘蛛图、网络图)是显示三个或更多数量变量的多元 数据的另一种方法。雷达图的问题是它们基于非公共轴和圆周网格线,这使得比较任务非常困难。

用线条剧情很容易误导 PCP,但是他们讲的故事不一样。刷和重排序背后的思想是 PCP 特有的。此外,时间序列分析不适用于五氯苯酚,因为不可能重新排序。

总之:相邻轴之间的关系很容易看出来,但不相邻的轴之间就看不出来了。因此,揭示数据模式通常需要重新排序轴,并仔细选择彩色地图或画笔过滤器。当两个平行轴之间的线相互平行(X 形)时,两个变量之间存在正(负)关系。

平行坐标讲故事:化学性质影响葡萄酒质量

在之前发表在《走向数据科学》的一篇文章中(“气泡图,为什么&如何,用气泡讲故事”,https://Towards Data Science . com/Bubble-Charts-Why-How-f 96 D2 c 86d 167),我们分析了一场 Kaggle 比赛的数据,该比赛与葡萄酒质量探索和葡萄牙“Vinho Verde”葡萄酒的红色和白色变种分析有关。

数据可在 https://archive.ics.uci.edu/ml/datasets/Wine+Quality[获得,包括 4898 项记录,包括白葡萄酒和红葡萄酒的十种化学特性和一种物理特性。该项目的目的是评估以下哪些化学或物理特性影响葡萄酒的质量:固定酸度、挥发性酸度、柠檬酸、残糖、氯化物、游离二氧化硫、总二氧化硫、密度、pH 值、硫酸盐和酒精等级。这组葡萄酒由三位专家评估,他们为每种葡萄酒提供了 0(差)到 10(优)之间的质量分数。表 1 显示了数据集的前五条记录。](https://archive.ics.uci.edu/ml/datasets/Wine+Quality)

表 1:葡萄酒数据集的前五条记录

在文章的最后,我们声称酒精等级和残糖水平是区分低质量葡萄酒和高质量葡萄酒的两个最重要的参数。现在还有待观察,是否有任何其他化学参数在决定最终产品的质量中起主要作用。

为了回答这个问题,我们决定使用五氯酚,因为剩余的八种化学性质被记录为定量变量,我们希望同时分析它们。

我们开发了以下程序:

**首先安装 Anaconda,这是一个用于 Python 计算和数据分析等任务的跨平台 Python 发行版。然后导入以下库:Pandas、Numpy、Matplotlib、Scypy 和 Scikit-learn。使用 read_csv() 函数读取并解析文件。检查缺失的记录并寻找数据集的形状:有 4898 条记录和 13 列。十列对应化学性质(固定酸度、挥发性酸度、柠檬酸、残糖、氯化物、游离二氧化硫、总二氧化硫、pH、硫酸盐和酒精等级)。一栏对应物理属性(密度),另一栏与质量分数相关,最后一栏表示红葡萄酒或白葡萄酒;

**接下来消除异常值(异常值),因为它们可能会在标准化过程中产生重大影响。使用 scipy.stats.zscore() ,用不同的阈值进行实验;

**将数据集分成高质量葡萄酒(质量分数为 7、8 和 9)和低质量葡萄酒(质量分数为 3、4 和 5);

**利用 scikit-learn 方法 MinMaxScaler 进行缩放阶段。记住最小最大缩放器从原始值重新缩放数据,因此所有新值都在范围 0–1(# 4)内;

**使用 parallel_coordinates 绘图功能,Pandas 内置绘图功能,使用 Matplotlib 创建平行坐标图。必需的参数是帧、class_column颜色图。框架包括以下九列(质量分数+八个化学性质):质量、固定酸度、挥发性酸度、柠檬酸、氯化物、游离二氧化硫、总二氧化硫、pH 和硫酸盐。Quality 是 class_column(包含类名的列名)。选择两个不同的颜色图,一个用于高品质葡萄酒,另一个用于低品质葡萄酒地块;

**尝试重新排序。

我们得到了高品质葡萄酒的图 4 和低品质葡萄酒的图 5。高质量的葡萄酒显示出较低的氯化物和游离二氧化硫含量,较高的固定酸度和总二氧化硫含量。低质量的葡萄酒显示出较低的游离二氧化硫含量,较高的氯化物和挥发性酸度。

图 4:高品质葡萄酒的五氯苯酚。该图形是用 Matplotlib 开发的。

图 5:低品质葡萄酒的五氯苯酚。该图形是用 Matplotlib 开发的。

葡萄酒行业利用二氧化硫的抗氧化和抗菌特性,防止颜色变化,尤其是在白葡萄酒中。二氧化硫总量是衡量游离态和结合态二氧化硫的指标。二氧化硫还能改善口感,保留葡萄酒的果味和新鲜香气(#5)。由于消费者中不良反应的逐渐记录,二氧化硫的使用已成为一个有争议的问题,消费者可能对其存在轻度过敏(因此,在标签上注明其用途已成为一些葡萄酒法规的一部分)。

另一方面,中到高浓度的氯化物可能会给葡萄酒带来咸味,这可能会赶走潜在的消费者。挥发性酸度是由葡萄酒中发现的酸类化合物制成,呈现出一种香气,而不是在口感上发现的。过量的挥发性酸性物质会导致不良的感官效果(#5)。

几个化学特性决定了葡萄酒的感官特性。我们发现,二氧化硫、氯化物和挥发性酸度在决定最终产品质量方面起着重要作用。由于这些属性或多或少可以量化,五氯苯酚可以帮助生产商为更多的消费者开发高质量的葡萄酒。

如果你对这篇文章感兴趣,请阅读我以前的:

簇状和重叠条形图,为什么和如何

https://towards data science . com/clustered-overlapped-bar-charts-94 f1 db 93778 e

堆积条形图,为什么和如何,讲故事和警告

https://towards data science . com/stacked-bar-graphs-why-how-f1 b 68 a 7454 b 7

参考

1:M·德奥卡尼,“平行坐标和轴坐标:考虑平行坐标的几何变换方法和新的图形计算方法”。高迪尔-维拉尔斯,1885 年。

#2: A. Inselberg,“N 维坐标”,图片数据描述与管理,第 136 页,1980 年。

#3: R. Roberts 等,“平行坐标的智能刷图”,Latex 类文件学报,第 14 卷,第 8 期,2015 年 8 月。

#4: J. Brownlee,“如何在 Python 中使用 StandardScaler 和 MinMaxScaler 变换”,https://machinelementmastery . com/standard scaler-and-minmax scaler-Transforms-in-Python/

第五名:https://www.decanter.com/

并行神经网络与迁移学习

原文:https://towardsdatascience.com/parallel-neural-networks-and-transfer-learning-dbce24f2cf58?source=collection_archive---------19-----------------------

近距离观察迁移学习和一个有趣的用例

介绍

你好。这是我第一篇关于媒介的文章。我已经计划写这篇文章有一段时间了。我的主要动机是帮助简化,甚至可能提供一个模板,用于下一步构建复杂的神经网络,除了您可能已经构建的特定架构中的神经元之外,还涉及并行神经元。这是因为尽管在理论上看起来很简单,但构建、保存、加载和精炼(以后再训练)神经网络确实会在我们实际开始编码它们时形成绊脚石。希望这篇文章能帮助你更好地理解与这些相关的问题,并帮助你解决在开始深度学习时不时遇到的小问题。就这样,让我们开始我们的旅程。

对于那些刚开始学习或正在练习神经网络的人来说,你可能已经观察到,我们使用的大多数神经网络架构通常是前馈的,即张量从一层按顺序流向下一层。假设我们想要探索,在我们构建并训练我们的架构达到一定程度的满意后,如果我们在一个层中增加神经元的数量,会发生什么。这通常意味着从头再来,可能会浪费几个小时的训练时间。仅仅为了看到在特定层中添加几个神经元的效果,从头开始似乎是不合理的。这就是迁移学习的用武之地。简单地说,它的意思是,你想把你在学习一个特定任务时学到的东西转移到另一个任务中去。在神经网络的范式中,我们学习的东西是用训练后得到的权重值来表示的。

当我们开始更多地了解如何利用迁移学习时,大多数内置函数都有固定的神经架构,并包含用于重新加载权重并在新的上下文中更新它们的代码。要想弄清楚将它应用到您的定制模型的细节,很可能需要几个小时或几天的时间,仔细琢磨网上的多个例子。我自己已经这样做了,我相信将我所学的东西都集中在一个地方,肯定会帮助任何想要更多地实践迁移学习以及探索增强神经网络的另一种替代方法的人。就这样,让我们开始我们的例子。

我假设您熟悉 PyTorch 中关于构建神经网络的教程,可从以下链接获得:https://py torch . org/tutorials/beginner/blitz/cifar 10 _ tutorial . html。要了解现有流行架构的迁移学习基础,请参考链接:https://py torch . org/tutorials/初学者/transfer _ learning _ tutorial . html。我强烈建议您访问这些链接和其他可用的链接进行实践,并形成一个训练神经网络架构的全面的想法。

我们的场景

假设我们现在想要创建 CIFAR 10 教程中描述的网络的副本,并将其与我们的训练版本并行放置,为图像分类的相同问题创建一个更大的网络。我们当前的模型在概念上是这样的:

教程中简单的前馈神经网络。来源:这是我自己用 MS Paint 画的概念图。

该图的张量板描述揭示了以下内容:

我电脑上模型的张量板表示。

我们现在的目标是构建一个如下所示的神经网络架构:

并行前馈神经网络——本质上是并排放置的模型的核心。来源:这是我自己用 MS Paint 画的概念图。

我们还希望这个新结构的上部子部分包含与通过执行教程获得的权重相同的权重。

把它编码

让我们看看帮助我们实现这种结构的代码:

import torch
import torchvision
import torchvision.transforms as transformstransform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform)trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,shuffle=True, num_workers=0)testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform)testloader = torch.utils.data.DataLoader(testset, batch_size=4,shuffle=False, num_workers=0)classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')import matplotlib.pyplot as plt
import numpy as np# functions to show an image
def imshow(img):img = img / 2 + 0.5     # unnormalizenpimg = img.numpy()plt.imshow(np.transpose(npimg, (1, 2, 0)))plt.show()# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))import torch.nn as nn
import torch.nn.functional as Fclass Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.pool = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):x = self.pool(F.relu(self.conv1(x)))x = self.pool(F.relu(self.conv2(x)))x = x.view(-1, 16 * 5 * 5)x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return xnet = Net()
PATH = './cifar_net.pth'
net.load_state_dict(torch.load(PATH))

到目前为止,我们已经重新创建了从教程中学习到的模型,并为我们训练和加载了权重,以复制到我们的新网络中。

下面的代码构建了我们需要的架构。

class SideNet(nn.Module):def __init__(self):super(SideNet, self).__init__()self.pool = nn.MaxPool2d(2, 2) self.conv11 = nn.Conv2d(3, 6, 5)self.conv12 = nn.Conv2d(6, 16, 5)self.conv11.weight.data.copy_( net.conv1.weight.data)self.conv12.weight.data.copy_(net.conv2.weight.data)self.conv21 = nn.Conv2d(3, 6, 5)self.conv22 = nn.Conv2d(6, 16, 5)self.fc11 = nn.Linear(16 * 5 * 5, 120)self.fc12 = nn.Linear(120, 84)self.fc11.weight.data.copy_(net.fc1.weight.data)self.fc12.weight.data.copy_(net.fc2.weight.data)self.fc21 = nn.Linear(16 * 5 * 5, 120)self.fc22 = nn.Linear(120, 84)self.fc3 = nn.Linear(168,10)def forward(self, x):y = self.pool(F.relu(self.conv11(x)))y = self.pool(F.relu(self.conv12(y)))y = y.view(-1, 16 * 5 * 5)y = F.relu(self.fc11(y))y = F.relu(self.fc12(y))x = self.pool(F.relu(self.conv21(x)))x = self.pool(F.relu(self.conv22(x)))x = x.view(-1, 16 * 5 * 5)x = F.relu(self.fc21(x))x = F.relu(self.fc22(x))out = self.fc3(torch.cat((x,y),dim=1))return out# create a new model
net1 = SideNet()

我们现在已经创建了我们的网络架构,并在类 SideNet()的 forward 函数中定义了网络中的张量流。

self.conv11.weight.data.copy_( net.conv1.weight.data)self.conv12.weight.data.copy_(net.conv2.weight.data)self.fc11.weight.data.copy_(net.fc1.weight.data)self.fc12.weight.data.copy_(net.fc2.weight.data)

这段代码片段在很多方面都很关键。你可能会立刻意识到这里发生了什么,因为这是迁移学习中基本发生的事情。我们刚刚将训练好的网络的权重复制到新结构的上部子部分。瞧啊。

我们现在可以选择保持这些权重不变,通过设置 requires_grad = False(实质上是冻结那些层的权重,这些层的权重是从我们训练的网络中复制的)或者在训练我们的新架构时更新它们。因为我只训练了几个纪元的网络,所以我将训练我们架构的两个子部分的权重。最初只训练一个时期的原因将在以后变得清楚。

#check weights
print(net.fc2.weight.data)
print(net1.fc12.weight.data)
print(net1.fc22.weight.data)#for param in net.parameters():
#    param.requires_grad = False
from torch.utils.tensorboard import SummaryWriter# default `log_dir` is "runs" - we'll be more specific here
writer = SummaryWriter('runs/temp')# write model to tensorboard
writer.add_graph(net1, images)writer.close()# train the new model
import torch.optim as optimcriterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net1.parameters(), lr=0.01)for epoch in range(1):  # loop over the dataset multiple timesrunning_loss = 0.0for i, data in enumerate(trainloader, 0):# get the inputs; data is a list of [inputs, labels]inputs, labels = data# zero the parameter gradientsoptimizer.zero_grad()# forward + backward + optimizeoutputs = net1(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()# print statisticsrunning_loss += loss.item()if i % 2000 == 1999:    # print every 2000 mini-batchesprint('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 2000))running_loss = 0.0print('Finished Training')correct = 0
total = 0
with torch.no_grad():for data in testloader:images, labels = dataoutputs = net1(images)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum().item()print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))
#check weights
print(net.fc2.weight.data)
print(net1.fc12.weight.data)
print(net1.fc22.weight.data)

这里,优化器的参数设置如下:学习率= 0.01,没有使用动量。我使用相同的参数来训练初始网络。这是因为当我们并排查看新网络和初始网络的权重时,我们需要检查旧网络的权重是否被复制,新网络的权重是否已被适当初始化,以及在训练新网络的权重时,初始网络的权重是否没有改变。最后一个短语是关键,有许多方法可以实现前一句中的前两个短语,但它们通常也会导致修改初始网络的权重!例如,如果使用以下代码片段:

self.conv11.weight.data = net.conv1.weight.dataself.conv12.weight.data = net.conv2.weight.dataself.fc11.weight.data = net.fc1.weight.dataself.fc12.weight.data = net.fc2.weight.data

让我们看看 TensorBoard 推断出的结构:

我电脑上模型的张量板表示。

它确实符合我们试图建立的东西。太好了!

验证我们对实际情况的理解

作为验证步骤,让我们打印两个网络的 FC2 层(全连接 2)的权重值:

print(net.fc2.weight.data) # before train
tensor([[-2.5432e-03, -6.9285e-02,  7.7019e-02,  ...,  2.8243e-02,4.9399e-02, -8.7909e-05],[-7.2035e-02, -1.2313e-03, -8.9993e-02,  ...,  1.8121e-02,-6.1479e-02, -3.8699e-02],[-6.3147e-02,  5.5815e-02, -6.0806e-02,  ...,  3.3566e-02,7.6486e-02,  7.3699e-02],...,[ 1.9772e-03, -1.8449e-02,  6.8946e-02,  ..., -2.1011e-02,7.5202e-02,  4.1823e-02],[ 2.9912e-02, -7.9396e-02, -8.7561e-02,  ...,  4.6011e-02,-9.0685e-02,  4.1302e-02],[-1.8297e-02, -7.3356e-02,  4.7250e-02,  ..., -7.5147e-02,-6.4722e-02,  6.0243e-02]])print(net.fc2.weight.data) # after train
tensor([[-0.0151, -0.0470,  0.1057,  ...,  0.0288,  0.0280,  0.0171],[-0.0720, -0.0029, -0.0907,  ...,  0.0181, -0.0630, -0.0408],[-0.0417,  0.0548, -0.1226,  ...,  0.0335,  0.0679,  0.0900],...,[ 0.0074, -0.0028,  0.0292,  ..., -0.0218,  0.0754,  0.0473],[ 0.0307, -0.0784, -0.0875,  ...,  0.0460, -0.0903,  0.0510],[-0.0252, -0.0824,  0.0380,  ..., -0.0744, -0.0741,  0.1009]])In our new model code, before train,
print(net.fc2.weight.data)
print(net1.fc12.weight.data)
print(net1.fc22.weight.data) tensor([[-0.0151, -0.0470,  0.1057,  ...,  0.0288,  0.0280,  0.0171],[-0.0720, -0.0029, -0.0907,  ...,  0.0181, -0.0630, -0.0408],[-0.0417,  0.0548, -0.1226,  ...,  0.0335,  0.0679,  0.0900],...,[ 0.0074, -0.0028,  0.0292,  ..., -0.0218,  0.0754,  0.0473],[ 0.0307, -0.0784, -0.0875,  ...,  0.0460, -0.0903,  0.0510],[-0.0252, -0.0824,  0.0380,  ..., -0.0744, -0.0741,  0.1009]])
tensor([[-0.0151, -0.0470,  0.1057,  ...,  0.0288,  0.0280,  0.0171],[-0.0720, -0.0029, -0.0907,  ...,  0.0181, -0.0630, -0.0408],[-0.0417,  0.0548, -0.1226,  ...,  0.0335,  0.0679,  0.0900],...,[ 0.0074, -0.0028,  0.0292,  ..., -0.0218,  0.0754,  0.0473],[ 0.0307, -0.0784, -0.0875,  ...,  0.0460, -0.0903,  0.0510],[-0.0252, -0.0824,  0.0380,  ..., -0.0744, -0.0741,  0.1009]]) tensor([[ 0.0864,  0.0843,  0.0060,  ...,  0.0325, -0.0519, -0.0048],[ 0.0394, -0.0486, -0.0258,  ...,  0.0515,  0.0077, -0.0702],[ 0.0570, -0.0178,  0.0411,  ..., -0.0026, -0.0385,  0.0893],...,[-0.0760,  0.0237,  0.0782,  ...,  0.0338,  0.0055, -0.0830],[-0.0755, -0.0767,  0.0308,  ..., -0.0234, -0.0403,  0.0812],[ 0.0057, -0.0511, -0.0834,  ...,  0.0028,  0.0834, -0.0340]])After training,
print(net.fc2.weight.data)
print(net1.fc12.weight.data)
print(net1.fc22.weight.data)tensor([[-0.0151, -0.0470,  0.1057,  ...,  0.0288,  0.0280,  0.0171],[-0.0720, -0.0029, -0.0907,  ...,  0.0181, -0.0630, -0.0408],[-0.0417,  0.0548, -0.1226,  ...,  0.0335,  0.0679,  0.0900],...,[ 0.0074, -0.0028,  0.0292,  ..., -0.0218,  0.0754,  0.0473],[ 0.0307, -0.0784, -0.0875,  ...,  0.0460, -0.0903,  0.0510],[-0.0252, -0.0824,  0.0380,  ..., -0.0744, -0.0741,  0.1009]])tensor([[-0.0322, -0.0377,  0.0366,  ...,  0.0290,  0.0322,  0.0069],[-0.0749, -0.0033, -0.0902,  ...,  0.0179, -0.0650, -0.0402],[-0.0362,  0.0748, -0.1354,  ...,  0.0352,  0.0715,  0.1009],...,[ 0.0244, -0.0192, -0.0326,  ..., -0.0220,  0.0661,  0.0834],[ 0.0304, -0.0785, -0.0976,  ...,  0.0461, -0.0911,  0.0529],[-0.0225, -0.0737,  0.0275,  ..., -0.0747, -0.0805,  0.1130]])tensor([[ 0.0864,  0.0843,  0.0060,  ...,  0.0325, -0.0519, -0.0048],[ 0.0390, -0.0469, -0.0283,  ...,  0.0506,  0.0030, -0.0723],[ 0.0571, -0.0178,  0.0411,  ..., -0.0027, -0.0389,  0.0893],...,[-0.0763,  0.0230,  0.0792,  ...,  0.0337,  0.0065, -0.0802],[-0.0756, -0.0769,  0.0306,  ..., -0.0235, -0.0413,  0.0810],[ 0.0048, -0.0525, -0.0822,  ...,  0.0019,  0.0785, -0.0313]])

因此,我们可以观察到,在训练新模型时,我们的初始模型的参数权重被复制,但没有改变。此外,复制了权重的层在训练后改变了权重,从而验证了我们的健全性检查。

我们现在已经建立了一个更复杂的模型,并且能够并行地重用我们的权重。当然,如果想要中间并行,只需要改变类 SideNet()的 forward 函数中张量的流向即可。

另一个例子

例如,假设我们希望保留卷积层,但在此之后引入两条平行路线。我们想要:

在神经网络之间引入并行性。来源:这是我自己用 MS Paint 画的概念图。

类 SideNet()现在看起来如下:

class SideNet(nn.Module):def __init__(self):super(SideNet, self).__init__()self.pool = nn.MaxPool2d(2, 2)self.conv11 = nn.Conv2d(3, 6, 5)self.conv12 = nn.Conv2d(6, 16, 5)self.conv11.weight.data.copy_(net.conv1.weight.data)self.conv12.weight.data.copy_(net.conv2.weight.data)self.fc11 = nn.Linear(16 * 5 * 5, 120)self.fc12 = nn.Linear(120, 84)self.fc11.weight.data.copy_(net.fc1.weight.data)self.fc12.weight.data.copy_(net.fc2.weight.data)self.fc21 = nn.Linear(16 * 5 * 5, 120)self.fc22 = nn.Linear(120, 84)self.fc3 = nn.Linear(168,10)def forward(self, x):y = self.pool(F.relu(self.conv11(x)))y = self.pool(F.relu(self.conv12(y)))z = y.view(-1, 16 * 5 * 5)y = F.relu(self.fc11(z))y = F.relu(self.fc12(y))x = F.relu(self.fc21(z))x = F.relu(self.fc22(x))out = self.fc3(torch.cat((x,y),dim=1))return out
# create a new model
net1 = SideNet()

TensorBoard 的描绘证实了我们想要建造的东西:

在我的电脑上对我们改进的并行神经网络的张量板描绘。

我希望所有这些例子能让你对编写复杂的神经网络充满信心,并成为你机器学习之旅中的关键垫脚石。感谢阅读:)

使用消息传递接口(mpi4py)的 Python 并行编程

原文:https://towardsdatascience.com/parallel-programming-in-python-with-message-passing-interface-mpi4py-551e3f198053?source=collection_archive---------8-----------------------

为超级计算机准备好您的代码。没那么难。

照片由 Carol Jeng 在 Unsplash 上拍摄

您知道您可以编写并行 Python 代码,在您的笔记本电脑和超级计算机上运行吗?你可以,而且没有你想象的那么难。如果您已经为异步并行化编写了代码,那么您甚至不需要进行太多的重构。

高性能计算(HPC)将任务分配到数千个 CPU 上(与笔记本电脑上的 4–8 个 CPU 形成对比),以实现显著的性能提升。CPU 使用消息传递接口(MPI)进行通信和传递数据。当您编写代码将任务分配给多个内核同时运行时,在您的笔记本电脑上也使用了相同的原则。本文将演示如何使用 MPI 和 Python 来编写可以在您的笔记本电脑或超级计算机上并行运行的代码。

安装 MPI

您需要为您的操作系统安装一个 MPI 应用程序。对于 Windows 用户,我建议直接从微软安装 MPI。对于 Mac 和 Linux 用户,我建议安装 OpenMPI 。Windows 用户必须将 MPI 安装目录添加到路径变量。

要测试您的安装,请在终端窗口中键入mpiexec (Windows)或mpirun (Mac/Linux,但请检查安装文档),然后按“Enter”键。如果您已正确安装,这将生成一条包含使用信息的消息。当你在终端时,也输入python并按下‘回车’。这应该会启动一个交互式 Python 会话。如果没有,您需要安装或配置 Python。

安装 mpi4py

mpi4py是一个 Python 模块,允许您与您的 MPI 应用程序进行交互(mpiexecmpirun)。和任何 Python 模块(pip install mpi4py等)一样安装。).

一旦你安装了 MPI 和mpi4py,你就可以开始了!

一个基本例子

使用 MPI 运行 Python 脚本与您可能习惯的略有不同。使用mpiexecmpirun,每一行代码将由每个处理器运行,除非另有说明。让我们制作一个“hello world”示例来演示 MPI 基础知识。

创建一个新的 python 脚本(.py文件)。导入mpi4py并使用MPI.COMM_WORLD来获取关于所有可用于运行您的脚本的处理器的信息(当调用脚本时,这个数字被传递给 MPI 应用程序)。COMM_WORLD访问可用于分配工作的进程数量(等级/处理器),以及关于每个处理器的信息。给出了为运行我们的脚本而分配的队列或处理器的总数。rank给出当前执行代码的处理器的标识符。下面的print语句将为作业中使用的每个处理器打印一次。

通过打开终端,导航到包含该脚本的目录,并执行以下命令来执行该脚本:

mpiexec -n 4 python mpi_hello_world.py

n -4指定要使用的处理器数量。在这个实例中,我使用了 4 个处理器,这意味着 print 语句将执行 4 次。注意,等级不是按数字顺序打印出来的,所以您需要确保您的代码可以异步运行。换句话说,不可能知道哪个处理器将首先启动或完成,因此您的代码需要以这样一种方式进行组织,即结果不依赖于可能在不同处理器上计算的值。

Hello world from rank 2 of 4
Hello world from rank 3 of 4
Hello world from rank 0 of 4
Hello world from rank 1 of 4

现在,更新脚本,以便它为不同的等级输出不同的消息。这是使用逻辑语句(ifelifelse)完成的。

我们现在得到 0 级和 1 级的不同消息。

First rank
Hello world from rank 0 of 4
Not first or second rank
Hello world from rank 2 of 4
Not first or second rank
Hello world from rank 3 of 4
Second rank
Hello world from rank 1 of 4

发送和接收数组

sendrecv功能分别将数据从一个处理器发送到另一个处理器,并从一个处理器接收数据。许多数据类型可以通过这些函数传递。这个例子将特别关注发送和接收numpy数组。SendRecv函数(注意大写字母“S”和“R”)是专用于numpy数组的。有关基本sendrecv的示例,请参见[mpi4py](https://mpi4py.readthedocs.io/en/stable/tutorial.html) 文档。

在上一篇文章中,我用multiprocessing模块演示了并行处理。我们将在这个例子中使用相同的函数。

[## 多处理 Python 中的异步并行编程

一种在个人计算机上加速代码的灵活方法

towardsdatascience.com](/asynchronous-parallel-programming-in-python-with-multiprocessing-a3fc882b4023)

在同一个目录中创建两个新的 Python 脚本。说出一个my_function.py和另一个mpi_my_function.py的名字。在my_function.py中,实现上面链接的文章中的功能。你的脚本应该是这样的。这是一个简单的函数,用暂停来模拟长时间的运行。

这些段落解释了my_function的并行化程序。代码在下面的要点中给出(带注释)。在mpi_my_function.py中导入my_functionmpi4pynumpy。然后从MPI.COMM_WORLD得到大小和等级。使用numpymy_function创建随机参数值。所有处理器上都有params变量。现在划分参数列表,将数组的一部分分配给每个进程(或等级)。我特意将params (15)中的行数奇怪地被处理器(4)的数量整除,因此我们必须做一些额外的数学运算来分解params。现在每个处理器都有一个变量来索引它在params数组中的块的startstop位置。

我们希望最终结果是一个数组,其中包含每个参数集的参数值和函数结果。创建一个空数组,local_results,其行数与参数数组相同,并增加一列来存储结果。然后对每个参数集运行my_function,并将结果保存在结果数组中(local_results)。现在每个处理器都有了它的params数组块的结果。

必须收集结果以创建最终数组,其中包含每个原始参数组合的结果。将每个等级的local_results数组发送到等级‘0’,在那里它们被组合成一个数组。当使用Send时,指定要发送到的秩,dest,并指定一个tag(唯一的整数),以便接收秩知道要检索哪个值(如果您最终执行多个Send,这一点很重要)。

对于接收秩(0),遍历所有其他秩,创建一个大小为要接收的数组的空数组,并使用Recv从每个秩中检索发送的值,指定要接收的秩和tag。检索到数组后,将其添加到现有值中。打印出最终的数组,确保它看起来是正确的。我们完事了。

使用以下命令运行上面的脚本:

mpiexec -n 4 python mpi_my_function.py

结果应该类似于:

results
[[7.58886620e+00 5.62618310e+01 9.09064771e+01 3.33107541e+03][2.76707037e+01 4.03218572e+01 2.20310537e+01 3.08951805e+04][7.82729169e+01 9.40939134e+01 7.24046134e+01 5.76552834e+05][9.88496826e+01 6.91320832e+00 1.59490375e+01 6.75667032e+04][8.94286742e+01 8.88605014e+01 5.31814181e+01 7.10713954e+05][3.83757552e+01 4.64666288e+01 3.72791712e+01 6.84686177e+04][9.33796247e+01 1.71058163e+01 2.94036272e+00 1.49161456e+05][1.49763382e+01 6.77803268e+01 7.62249839e+01 1.52787224e+04][7.42368720e+01 8.45623531e+01 6.27481273e+01 4.66095445e+05][6.76429554e+01 5.95075836e+01 9.82287031e+00 2.72290902e+05][4.94157194e+00 7.38840592e+01 3.70077813e+00 1.80788546e+03][2.71179540e+01 2.94973140e+00 2.86632603e+01 2.19784685e+03][2.92793532e+01 9.90621647e+01 9.45343344e+01 8.50185987e+04][1.20975353e+01 8.89643839e+01 7.13313160e+01 1.30913009e+04][8.45193908e+01 4.89884544e+01 5.67737042e+01 3.50007141e+05]]

结论

您可能已经注意到,并行运行一个 4 行函数需要 43 行代码。似乎有点矫枉过正。我们并行化了一个简单的函数,但这实际上是一个更复杂的例子,因为需要进行操作来获得所需的输出格式。这个例子作为更复杂函数的并行化模板。一般来说,我将编写一个 Python 模块来运行我的模型/分析,然后在并行化脚本(上面的 43 行要点)中设置并调用模块中的一个函数(完成所有工作)。您可以运行非常复杂的分析,而无需向我们在此创建的脚本添加太多代码。一旦你让这个代码在你的个人机器上运行,它就可以在大多数超级计算机上运行,而不需要太多额外的工作。

并行快乐!

并行编程:Python 中的多重处理

原文:https://towardsdatascience.com/parallel-programming-multiprocessing-in-python-61c596b366e0?source=collection_archive---------33-----------------------

在这个计算能力贪婪的时代,我们往往会忘记在自己的电脑上使用我们可以利用的能力

PC via Flickr

一般来说,程序员、游戏玩家、科学家、软件开发人员和大多数知道如何使用计算机的人对计算能力的渴望是巨大的。我们一直在寻找计算强度更低、效率更高的应用。这使我们能够更有效地利用我们的计算机设置。

然而,我们中的许多人并没有充分利用计算机上已经可用的计算能力。在需要的时候利用这种能力可以带来指数级的更好的性能,通常,通过一些代码的改变,你可以将进程运行速度提高 2-3 倍。你会问我们如何做到这一点?好吧,我们开始吧。

这个博客主要关注并行编程。即同时在多个处理器上运行程序。当你运行你的程序时,它通常使用你计算机中的一个内核。但是,大多数计算机都有多个内核。根据您的处理器,它可能是双核、四核、八核,或者可能包含更多内核。如果(比方说)你有一个四核处理器,只在一个内核上运行程序,你实际上放弃了其他三个内核,因此计算能力是你正在使用的三倍。理论上,使用所有这些内核可以将您的任务速度提高四倍。

多重处理

然而,这并不简单,否则软件公司将一直使用所有的内核来获得更好的性能。如果你想提高程序的性能,你需要确保它可以并行化。也就是说,它可以同时在不同的内核上运行。

让我们举一个简单的例子来理解这一点。假设你要生产一个产品,你把它的生产分成四个阶段。如果只有在阶段 1 已经完成的情况下才能从阶段 1 进入阶段 2,然后只有在阶段 2 完成的情况下才能从阶段 2 进入阶段 3,以此类推。那么这个过程就是一个连续的过程,因为你必须遵循一个序列来执行你的指令。然而,如果你能把生产分成四个部分并分配给不同的工人,那么这个过程就可以并行化。例如,为一个玩具构建四个组件,这些组件一旦完成就可以连接起来。

一旦您确定您的程序可以并行化,下一步就是为它编写代码。我不会在这个博客中写代码,但是,这个博客的代码可以在这个 Github repo 中找到。我选择 python 来编写代码,我使用了多处理模块来在多个处理器上运行程序。

[## Khan saadbinhasan/Python 中的并行编程多处理

程序乘以 mXn 矩阵与单核以及多核。该计划产生两个随机…

github.com](https://github.com/khansaadbinhasan/Parallel-Programming-MultiProcessing-in-Python/blob/master/README.md)

在本期节目中,我们将看到并行编程的两个应用。首先是矩阵乘法,它可以很容易地并行化,接下来我们将看到前缀和扫描,乍一看似乎是一个顺序问题,但可以并行化,以在多个处理器上运行。

矩阵乘法

将两个矩阵相乘相当简单,是大多数编程入门课程的一部分——从第一个矩阵中选择一行,从第二个矩阵中选择一列,将相应的元素相乘并相加,得到第一个元素,然后移到下一列,以此类推,得到下一个元素。

这里,人们可能会注意到,给定两个矩阵 A(mXn)和 B(nXr)以及它们的合成和矩阵 C(mXr),为了得到元素 C(i,j ),人们只需要考虑矩阵 A 的第 I 行和矩阵 B 的第 j 列就可以得到所需的矩阵 C 的元素。因此,我们是否已经计算了元素 C(1,1)来计算元素 C(1,2)并不重要。

因此,可以将程序分成不同的进程,并在不同的处理器上运行。这可以导致程序运行速度的显著提高,因为矩阵乘法在许多应用中是如此重要的操作,例如机器学习、科学模拟、游戏等。回报是巨大的。

现在,尽管这听起来很简单,但在代码中实现时,我们仍然需要小心一些事情。首先要做的事情之一是决定哪些计算将在哪个内核上运行。您可以决定按行或按列划分矩阵。我们应该按顺序做。也就是说,首先,我们取第一个矩阵,取其一定数量的行,并将其与第二个矩阵中的所有列相乘,同时对不同内核上的不同行执行此操作。

例如,假设我们有 A(4X3)和 B(3X5)两个矩阵,我们将 A 的第一行的计算负载分布在一个处理器上,第二行分布在第二个处理器上,依此类推。但是,如果我们的行数超过了处理器的数量,那该怎么办呢?例如,A(7×4)和 B(4×5),这里,我们为我们做一个除矩阵的函数。也就是说,它决定了矩阵如何被划分以在不同的处理器上运行。

实现该函数的一种方法是从 0 到 r 开始第一次除法,其中 r 可以通过整数除法(总行数/处理器数)来计算,然后是从 r 到 r +整数除法(总行数/处理器数),其中现在的总行数是之前的总行数减去已经要执行的行数,我们少了一个处理器,以此类推。

让我们举个例子来理解这一点

然后,第一次除法将从 0 到(7/4)即 0 到 1现在 R = R-1 = 6,N = N-1 = 3因此,第二次除法将从 1 到 1+(6/3)即 1 到 3现在 R = R-2 = 4,N = N-1 = 2因此,第三次除法将从 3 到 3+ (4/2) i 3 到 5现在 R = R — 2 = 2,N = N — 1 = 1因此,第三次除法将是从 5 到 5+(2/1)即 5 到 7因此,除法将是从:(0 到 1)、(1 到 3)、(3 到 5)和(5 到 7)

注:此处第一项是非包容性的,矩阵从索引 1 开始。因此,第一行在第一处理器上执行,而不是在第二处理器上执行。

现在,我们可以将矩阵分成所需的行,并在不同的内核上执行。我在随机生成的 100X100 矩阵上运行上述程序,发现加速几乎是 2.75 倍。那么,加速到底是什么?

这是一种方法来衡量你的算法有多快,相比之下,一个类似的算法顺序运行。我们怎么做呢?我们首先计算执行顺序程序的时间和执行并行程序的时间。然后我们将第一次得到的时间除以第二次得到的时间,这就是我们的加速比,也就是说,我们的程序比顺序程序快多少。

从理论上讲,给定四个内核应该会将算法的性能提高四倍,但是,当我们试图并行运行这些进程时,会产生额外的开销。例如,我们必须生成多个进程并进行额外的处理,因为在这种情况下,我们将矩阵行划分为在不同的处理器上运行。此外,由于我们将写入一个公共内存阵列,因此在写入结果时可能会有冲突,这也可能会导致速度变慢。另一个原因可能是这些过程需要不同的时间来执行。例如,在上面的例子中,不是所有的行都有相同的大小,因此需要不同的时间来执行。

我建议你去我的 GitHub repo 下载文件夹,按照说明运行程序。当你使用它的时候,在 ubuntu 中打开名为“系统监视器”的软件,或者在 windows 中打开名为“任务管理器”的软件。转到显示不同处理器使用情况的选项卡。当顺序程序运行时,它应该是这样的。

在顺序算法中仅使用一个内核

这表明当顺序乘法运行时,只有一个内核在使用。而运行并行计算会导致使用所有四个内核。你可以在下面的截图中看到。

并行算法中使用的所有内核

现在,我们已经执行了矩阵相乘的程序,并确保它可以在多个处理器上执行。我们现在将关注一个更反直觉的问题,即前缀求和。

前缀总和扫描

扫描可能是并行编程中最重要的主题之一。理解什么是扫描很简单,但是,很难找到一种方法来并行化它,因为它看起来本质上是顺序的。

给定 n 个元素的列表,第 I 个元素的扫描被定义为在它之前的所有 i-1 个元素的总和,根据扫描的类型包括或不包括第 I 个元素。在这篇博客中,我们将看到一个包含第 I 个元素的全面扫描。例如,列表[1,2,3,4,5,6,7,8]的扫描将是[1,3,6,10,15,21,28,36]。这个操作可能看起来非常简单,但它是相当常见的,它不限于加法,你可以应用大量的运算,因此你正在做的是找到一种方法来应用一些运算到一个数字列表,但不是顺序地做,而是并行地做。

计算扫描顺序是足够容易的,我们必须维护一个变量运行总和,并添加每个元素一个接一个,并取代它。然而,当试图并行化这个问题时,没有想到立即的解决方案。我们要看一个算法,对思考这个问题有帮助。这种算法以最早提出它的人的名字命名为希利斯-斯蒂尔斯算法。

从这个算法开始,首先,把第 I 个位置的每个元素加到第 i + 1 个位置的元素上,更新第(i+1)个元素的结果。如果没有元素替换该元素,则按原样复制它。在下一阶段,将第 I 个元素添加到第(i+2)个位置的元素,并更新第(i+2)个位置的元素。如果元素没有更新,请再次复制它。对第 I 个和第(i + 4)个元素再做一次,依此类推。

这里,我们在每个阶段取第 2r 元素,其中 r 是从 r = 0 开始的阶段号。停止条件将是当我们不能再把元素加在一起,因为 2r 大于或等于元素的数目。因此,总共有 log(N)个阶段,其中 N 是元素的总数。r 从 0 到 log(N)-1 不等,包括 0 和 log(N)-1。

这个算法为什么会起作用?好吧,让我们来看看下面这个来自 Udacity 并行编程课程的精彩视频的例子。让我们以第 5 个(1 索引)元素为例,即 5。在包含和扫描中,其最终值将为 15(即 1 + 2 + 3 + 4 + 5)。

第一步,我们用 4 加 5,得到 5+4 = 9。在第二步中,由于我们已经将前面的元素添加到我们的元素中,现在我们需要在它之前添加元素。即 3、2、1 等。但是在上一步中,我们已经将 3 加到了 2,即 3+2 = 5。这个元素现在位于原始元素之前的两个位置。因此,如果我们把它加到 9,我们得到 9 + 5 = 14 或 5 + 4 + 3 + 2 = 14。现在,我们已经添加了 5,4,3,2。因此,我们需要更进一步,也就是说,在 1 之前增加元素 4 步,因此我们得到总和 15。

但是如果我们在 1 之前有更多的元素,在这种情况下,1 所在位置的元素将包含它之前 3 个元素的总和。因此,很容易看出这将如何导致先前没有添加的那些元素的添加,而在每个阶段,任何元素都包含在其之前的 2^r 元素的总和(包括其自身)。

希利斯-斯蒂尔斯扫描

这个算法对并行化有什么帮助?在每个阶段,我们只关心将一个元素添加到当前元素,而不关心它之前的所有元素,因为在每个阶段,我们添加到当前元素的元素包含关于它之前的一些元素的信息,而在下一个阶段,我们添加的元素将包含关于更多元素的信息,最终我们将获得关于当前元素之前的所有元素的信息。因此,在每个阶段,我们只能处理一些元素,而忽略其他元素。这可以在不同的内核上完成。

为了并行化该算法,我们将遵循与矩阵乘法类似的方法,首先,我们创建一个函数来划分列表,我们需要将它分布在不同的内核上。我们可以使用与矩阵乘法几乎相同的算法。然后,我们可以将第 I 个元素添加到(i — 2^j)th 元素,其中 j 是我们从 0 迭代到 lg(N)的迭代变量。然而,这个算法将只对偶数个元素起作用,因为您可以通过取奇数个元素来验证。处理这个问题的方法是在元素个数为奇数的末尾再填充一个元素,一旦计算完成,就删除最后一个元素。

要查看实际的实现细节,请访问包含代码的 Github repo ,并按照 README.md 文件运行程序

为了更直观地理解这个算法,请看下面的视频,这个算法可以在这里找到。

【https://khansaadbinhasan.blogspot.com】最初发表于

R 中的并行 API 连接

原文:https://towardsdatascience.com/parallel-web-scraping-and-api-connection-a-way-to-save-lots-of-time-part-i-r-bf740f6cfbd0?source=collection_archive---------39-----------------------

节省大量时间的方法。

创建新数据集是数据科学家和分析师目前面临的挑战之一。创建数据集的一种流行方式是网上冲浪,并根据需要从不同的网站收集信息。但是您可能知道,这非常耗时,因此在不使用多个虚拟机或集群的情况下加速这一过程是您的数据科学家工具集的一部分。在这里,我们将深入探讨如何使用 r 进行并行 API 连接。

这是一个关于如何使用并行计算的简单指南。这个想法是,你的计算机的每个线程/工作者/核心使用不同的连接来访问网络,因此,你不需要等待 API 响应或动态网站的加载来开始抓取另一个。只需将简单的命令添加到代码中,并以巧妙的方式包装它,就可以加快速度,节省大量时间。

并行 API 连接

我们将从并行使用 R 和 API 连接开始。这将允许我们更有效地下载信息,就像在你的网络浏览器中打开多个标签一样。对于我们的例子,我们将使用 OMDB API 。这个 API 让您可以访问许多关于电影的信息,对于我们的测试,我们使用了 Poster API 来下载电影海报并将其保存在本地,以便我们可以在以后处理它们。

1.-加载库

第一步是加载所有需要的库。对于并行设置我们的代码,我们将使用, *future。*这个库设置了我们将要使用的并行方法。对于并行功能,我们选择, furr 包。这个包是 purrr 包的未来版本。

library(RCurl)
library(curl)
library(future)
library(furrr)

2.-创建一个函数

其次,我们需要创建一个新功能。这个函数将是我们进行 API 连接和下载的地方。在这里,我们可以将 API 连接代码更改为 web 抓取代码。

为了演示如何做,该函数将打开一个与 Poster API 的 curl 连接,并将一个图像下载到一个名为 images 的新目录中。

imgAPI <- '[http://img.omdbapi.com/?apikey=*[your-own-api-key]*'](http://img.omdbapi.com/?apikey=9c9e16a&i=tt')
rootDir <- 'images/'
get_img <- function(id){url <- paste0(imgAPI,str_pad(id, 7, pad = "0"))if(url.exists(url)){curl_download(url = url ,destfile = paste0(rootDir,'tt',id,'.png'))}
}

使用并行连接和传统的并行处理之间的一个区别是,您几乎可以肯定您的代码能够并行运行,因为通常连接本质上是独立的。

3.-在所有连接上运行 future_map

最后,我们需要在我们的链接列表上运行我们之前创建的函数。为了实现这一点,我们使用了 future_map ,一个并行版本的 map 函数。这就是并行连接发生的地方。

#load file with list of movie ids to create API links
links <- read_csv('links.csv')future_map(links,get_img)

重要:为了让我们的代码知道它需要并行运行,我们需要告诉它如何去做,以及它应该使用多少个不同的内核。未来库中有两个函数允许我们这样做:【可用资源() & 【计划()。第一个读取关于我们的计算机有多少内核的信息,第二个告诉代码有多少内核以及如何并行化未来的功能。

n_cores <- availableCores() - 1
plan(multiprocess, workers = cores)

为不属于您代码的其他计算机进程留出一个空闲的内核总是一个好的做法。

4.-测试和结果

使用之前定义的代码,我们将运行一个小测试,看看这些并行连接如何提高我们的下载速度。对于该测试,我们使用 4 种不同的配置:

  • 完全没有平行,使用正常的映射功能。
  • 多重处理计划和设置 3 个核心。
  • 多重处理计划和设置 5 个核心。
  • 多重处理计划和设置 7 个核心。

内核数量是根据 8 个内核的机器选择的,至少有 1 个内核空闲。

为了进行测试,我们在 3 个不同的场景中运行每个配置,以检查卷如何影响性能。这些场景基于我们将要下载的电影海报数量(500,1000,2500)。在每个场景中,我们运行 5 次,取下载所有电影的平均时间。

结果如下图所示。

作者图片

结论

该测试向我们展示了使用并行计算从 web 访问信息可以极大地丰富我们的工具包。作为数据科学家,我们有很多关于访问 API 以访问信息的项目,这是一种加速这一过程的方法。即使这个过程不是那么庞大,改进也是巨大的。

您可以在这个 GitHub 链接中访问该实验的代码。

R #1 中的并行化警告:性能问题

原文:https://towardsdatascience.com/parallelization-caveats-in-r-1-the-basics-multiprocessing-and-multithreading-performance-eb584b7e850e?source=collection_archive---------13-----------------------

R 中的多处理的介绍,以及一些很难注意到但可能严重影响性能的缺陷。

关于这部作品。我以一篇独立的文章开始这篇文章,总结我在研究项目中遇到的并行处理问题。在看到这篇文章变得相当长之后,我决定将它分成多个部分,每个部分涵盖一种特定的陷阱,在最好的情况下,这些陷阱会导致错误,或者在最坏的情况下,会导致明显的糟糕性能或看不见的后果。因此,您将[有希望]看到多篇文章,这些文章涵盖了这些陷阱以及我已经成功应用于解决我的问题的解决方案。本文讨论基本的设置和可能的性能问题。

手工摄影在 Unsplash 拍摄

我们大多数人在工作中都遇到过代码速度不够快的情况,因为它只使用了一个 CPU 内核,需要几个小时才能完成。为了解决这个问题,我们求助于传统的多重处理技术,希望它能弥补我们计算的缓慢。然后,在快得多的 30 分钟的运行结束时,我们看到一个错误,它根本没有告诉我们哪里出错了,可能类似于Error reading from connection 7(如果您来自搜索引擎,这不是涵盖这个特定错误消息的文章)。在本系列中,我将总结我在 R 中的并行性经验,并尝试指出在并行计算中可能会出错的地方。我不会深入讨论并行处理是如何工作的——尽管我将尝试至少定义我所使用的概念——本系列旨在收集在决定切换到并行模式时需要考虑和注意的事情。

在第一部分中,我将谈论为什么我们会转向并行工作流(只是为了给我们一点动力),然后我将展示一些在 R 中实现它的技术,最后我们将开始组合它们以在我们的计算机上释放完全的混乱,我们将看到为什么这个或那个不应该一起使用,或者为什么以某种方式做某事会减慢您的计算。好吧,也许我有点太戏剧化了,但是我最近设法冻结了一个 32 核服务器,给了它太多的事情去做——当然是不情愿的。

最终,我决定写这些文章,因为我自己在编写代码时遇到了这些问题,而且没有现成的食谱(至少我还没有找到一本)可以指出我犯的错误——有些可能是语言或特定于包的错误,但大多数错误很难找出——并给我一些如何解决它们的建议。虽然本系列的大部分内容包含特定于 R 的建议,但我将要讨论的一些问题是语言不可知的,这意味着如果您使用 MATLAB 或 Python 或 Assembly (hah)来做类似的工作,您可能会面临与我相同的问题。还要注意,我不是并行化大师(既不是也不是的 R 大师),所以如果您发现什么不正确的地方或者需要更好的解释,请不要犹豫,告诉我!

四个任务的顺序执行和并行执行的简化(理想)图(图片由作者提供)

简介:“为什么还要并行?”

你是否尝试过执行一个包含一些复杂数学运算的长循环?就像一系列的矩阵求逆,其结果被相乘,多个函数被调用,甚至可能解决一些二次优化问题,等等?如果你在代码运行的时候打开了任务管理器(或者在你喜欢的操作系统上打开了它),你可能会发现 R 进程并没有完全使用你的全部处理能力,而只是使用了一小部分。CPU 使用百分比可以从大约 50%(在 2 核 CPU 上)到 4–5%(在 24 个[逻辑]核上)不等。你可能会问一个关键的问题:

如果 R 使用了我 100%的 CPU,我的计算不会运行得更快吗?

答案很不幸只是:大概是。看,在我们开始让我们的代码使用更多的 CPU 之前,我们必须了解一些关于我们如何计算的事情,更重要的是,我们的计算结果是否相互依赖。一般来说,如果你有两个相互依赖的任务,那些不能并行执行(如果没有第一个的结果,第二个会怎么做?).否则,如果你的任务不相互依赖,它们可能并行运行。你也可以把你的任务想象成一个for循环的主体:如果你需要来自前一次迭代的数据,那就不能并行运行。

为了创建一个更实际的例子,我们将计算矩阵行的总和。是的,有一个叫做rowSums的函数可以更快地完成这项工作(你应该使用它来代替下面的实现),但是这个例子应该足够简单来帮助我们理解基础知识。有一种方法可以做到这一点:

这段代码将计算矩阵中每一行的总和,并将其存储在results向量中(请尽量避免像这样分配向量,因为它们将不得不动态增长,这是很昂贵的,一个额外的提示是使用results = numeric(nrow(bigMatrixWithLotsOfData))来代替——假设您知道结果将是数字)。因此,我们将依次计算每一行的总和,一个接一个。但是事情是,对于任何一个 **i** 我们不需要任何其他迭代的结果!因此,如果我们的计算不相互依赖,我们可以理论上并行运行它们,将一些工作交给我们的其他 CPU 内核!

顺便说一下,我会经常提到for循环,因为 R 中一个流行的并行解决方案也使用它们——不过,我们不要太超前了。现在,关于什么有助于无错并行(线程安全等等),将有更多的讨论,但这不是一个一般的并行计算讲座,而是关于 当进行并行处理时,什么可能出错

好的,那么并行计算行和需要什么呢?有几种方法可以实现它,但是所有的解决方案都涉及到立刻开始多重、 独立 计算(就像为每个i创建一个 R 实例)当它们都完成时,就把它们的结果粘在一起。现在,我将向您展示如何做到这一点。

R 中的并行处理:使用“foreach”的多处理

在 R 中,进行并行计算的一种典型方式是借助于foreach包(这里有更多关于如何使用它的信息)。它提供了一种便捷的方式将您的任务( jobs )分配给多个进程,而不需要考虑如何以及何时将某个任务安排给某个进程。当这些过程完成时,这个包还会帮助您将结果连接成一个列表或向量(或者实际上是任何东西)。就其本身而言,这可能还不够,因为您需要提供所谓的并行后端(处理进程的创建和销毁,以及它们之间的通信)。包doParallel提供了一个这样的后端。无需深入了解它们是如何工作的,这里有一段代码为我们做了并行行求和:

我插入了一些更长的注释来说明这些指令的用途。该代码片段将让您快速了解如何使用该包来运行并行计算。通常,您会希望以item = theListToProcess的形式向foreach结构提供一个列表,然后您可以在您的子流程中用item变量引用列表的当前元素——您可以为它选择(几乎)任何名称。

不幸的是,我们现实生活中的计算很少这么容易实现。也许我们正在运行复杂的模拟(计算多个矩阵的协方差,解决线性规划问题等等),我们的结果只有在执行了一些函数后才会出现。也许您已经创建了顺序运行的代码,现在您想让它并行运行。也许你让你的代码并行运行,但实际上比顺序运行要慢(是的,这可能发生,我们会看到)。很多事情都可能出错,但是如果你注意其中的几个,你就可以编写出引起麻烦的几率更低的代码。

首先,我可以并行化什么?

如果您已经有了一些代码,并且正在考虑通过并行执行来使它更快,那么停下来想想它计算最终结果的步骤是一个好主意。创建一个简单的流程图也很有帮助——看看下面的速写:

处理每日股票市场价格的程序的简化流程图(图片由作者提供)。

该图显示了从数据集的某些部分组装投资组合的过程(例如,基于 2020 年 6 月 1 日和 2020 年 6 月 5 日之间的数据创建投资组合,然后基于 2020 年 6 月 8 日和 2020 年 8 月 12 日之间的数据创建投资组合,以此类推),并汇总这些操作的结果。在绿色区域,我们可以看到组装投资组合的过程相互依赖,只依赖于预先获得的数据,因此我们可以重新安排它们并行运行。一般来说,for循环是开始观察的好地方:如果您没有将数据从一个迭代传递到另一个迭代(并且您也没有在循环之外修改数据*,您应该可以让那个循环并行运行(尽管尝试并行化一切很容易,请参见性能部分)。*

如果您已经嵌套了 for 循环,并希望将其中一个循环转换为并行任务,请确保您执行的是仍然可以独立运行的最外层循环(如果它不止循环几次)。

这可能是一项令人生畏的任务,而且真的没有通用的方法来做到这一点:你必须做出决定,将一些事情变成平行的,或者保持现状。或者,您可能需要重构代码,使其更易于并行化。现在——在这个冗长的介绍之后——让我们直入主题:

什么可能出错(第 1 部分)?

无意中问了太多你的 CPU 也就是性能问题

在本文的剩余部分,我们将看看一些看似微妙的问题,这些问题不一定会使 R 会话崩溃或抛出错误,而是会悄悄地削弱您的计算性能,甚至可能使您的计算机进入无响应状态。首先,我将讨论并行化的开销,这种开销随着并行执行的性能增长而慢慢减少。然后我们将了解为什么混合多种并行化技术是一个坏主意,最后我将向您展示两个边缘案例,如果与其他一些问题结合起来,可能会导致更多问题。

并行化不是免费的:开销

很容易将并行化视为解决所有性能问题的金锤。事实上,

为什么我不应该并行运行所有的事情呢?

问得好,但原因如下。很容易从上面的例子中得出结论,说“嗯,我有一个长度大于 100 的向量,让我们把它扔到 32 个进程上来计算一些东西”。问题是创建进程不自由,它们之间的通信也不自由。它们中的每一个都需要启动(至少在不分叉的时候),并且它们有自己的内存空间(Windows 上的一个基本 R 实例可以占用 30-50 MiB RAM,乘以 12 个进程就已经是 480-600 MiB 了——我们甚至还没有在它们上面加载包和数据!).如果您需要访问所有进程上的整个大型数据框架,那么需要将数据加载到所有进程上——不过,只需将真正需要的变量移动到您的进程上。如果您使用具有大量依赖项的包,它们将使用大约 12 倍多的 RAM——在我们的 12 进程示例中。您很快就会明白为什么我们需要将数据加载到我们所有的流程中。

还记得文章开头的这张图吗?这离现实又近了一步(图片由作者提供)。

因为我在 32 个内核的 Linux 服务器上使用了一个“SOCK”集群(即我没有分叉我的进程),我必须等到所有 32 个进程都正确初始化,这导致了大约 45 到 90 秒的等待时间:每个进程都必须加载多个包并调用一些函数来准备处理。在这种情况下,最好重新考虑启动时间(和增加的内存使用)是否真的值得多处理带来的性能提升。对我来说,这绝对是值得的,因为我解决了成千上万的二次规划问题:这里开销和并行执行时间的总和仍然比顺序运行时低得多。然而,对于小任务,选择更少的进程或者根本不并行会更有效率。

在下一节中,我们将看到另一种提高速度的方法,而不必求助于多重处理,以及它是如何引起更多麻烦的。

多线程×多处理=不好

如果你想让数学运算更快,从 base R 转换到微软 R Open (MRO) 可能是个不错的选择。它是 R 的一个略微修改的版本,依赖于一个不同的库(英特尔数学内核库(MKL) )来进行数学计算。了解微软 R Open 很重要的一点是:( 1)它与 base R 兼容,更重要的是,( 2)由于采用了英特尔 MKL,它通过以多线程的方式执行矩阵乘法和类似的矢量化任务,实现了更快的速度——可以在这里看到微软进行的性能比较。坚持住。什么,现在?

从概念上讲,所做的事情与我们在上面的行求和示例中所做的非常相似。多线程工作流,然而,创建单独的线程,而不是单独的进程(如同多重处理)。如果你不介意的话,我不会深入研究具体的技术差异,但我们也不要在这里留下一个黑洞。在多线程环境中,内存通常在计算(线程)之间共享,而在多处理环境中,每个进程都有自己的内存。如果您还记得上一节,这就是为什么我们必须初始化集群中的每个 R 进程:因为它们是独立的进程(实例),有自己的内存,所以每个进程都作为一个空的 R 实例启动,没有加载额外的包。一个进程可以有多个线程,所以这里也有一个层次结构,但就像我说的,这不是一个并行计算或操作系统大师级。

在高层次上,创建线程通常比创建进程便宜(CPU 和内存方面也是如此),但是对于线程,您必须非常小心内存,因为您可能会覆盖另一个线程正在处理的内容。但是在进程的情况下,由于独立的内存空间,这不是问题,但是您必须处理进程之间的通信(这是由并行后端和foreach完成的)。每一种都有它们的优点和缺点,但是知道你可能会在不知情的情况下使用它们可能会导致速度大幅下降就足够了。我们能把这叫做过度平行化吗?

我们来数一数。您正在使用 MRO (Microsoft R Open ),因为它在顺序工作流中更快,但是您注意到您的代码的一部分可以并行执行,所以您将并行foreach放入其中。您有一个 4 核 CPU (4 个逻辑核,没有超线程),因此您会产生 4 R 个进程。但是,您没有意识到的是,您正在创建 4 个 MRO 进程,这些进程可能没有被告知并行情况,因此它们每个都决定使用 4 个线程来进行计算。你开始进行大量矩阵求逆或乘法的并行计算,却突然意识到。只是。。这怎么可能?

事实是,你实际上使用了 4*4 = 16 个线程!CPU 能够同时运行的线程数量的四倍。结果,你的 CPU 在这些线程之间来回切换,大大降低了矩阵运算和并行执行的速度。它可能会减慢到顺序执行会更快完成的程度。

为了避免这个问题,您应该使用 MRO 的命令(setMKLthreads)将每个子进程上使用的线程数限制为 1。我将给你一个使用doParallel包实现这一点的完整例子。确保在实际的foreach计算之前运行下面的代码片段**!**

很好。试着再次运行你的计算,你可能会注意到它们变得更快了,就像我一样。哦,顺便说一下,clusterEvalQ只是在你所有的子进程上执行相同的代码(文档在这里,我稍后会谈到)。它可用于在您的流程上进行一些设置工作,如加载包和调整设置。

错过这一点的有趣之处在于你可能甚至不会注意到背景中发生的事情。您不会得到任何错误,但在某些时候,您的计算可能会大大减慢。只要您的进程没有同时碰到一些繁重的多线程部分,您可能会没事,但是一旦它们碰到了,您会发现您的进度条(如果您正在使用的话)停止了,只是盯着监视器,心想“嗯,它似乎不能再快了”。我的模拟似乎也停止了,我想这是因为我使用了 500×500 的矩阵——它们在 50×50 的矩阵下运行良好!一旦我告诉 MRO 停止在它的每个进程上使用多线程,我的并行执行甚至可以在大(500×500)矩阵上运行!我在 32 核服务器上运行这些,所以我实际上产生了 3232 个线程,太棒了。*

即使你不使用 MRO,你仍然可能遇到这个问题。看,例如data.table包也是多线程的,但是当文档说它可以检测它是否运行在一个分叉进程上并切换回单线程操作时,我有点担心明确提到的分叉。分叉是创建集群时的另一种方法,它克隆进程(在 Linux 上传递type = "FORK"makeCluster),但它在 Windows 上不起作用,所以我使用“SOCK”集群——我在 Windows 上开发我的代码,并在 Linux 服务器上运行它,这是最好的办法。为了扩展前面的代码,我们可以改为执行以下代码:

这应该足以让你开始多线程和多处理。请记住,您需要确保您在子进程上使用的每个包都以单线程模式运行。软件包通常会告诉你它们是否像data.table一样使用多线程。

顺便说一下,如果您想知道 MRO 在单线程上的性能,当切换到单线程操作时,它不会变得无用。它仍然使用英特尔的 MKL,即使在一个线程上,它也比 base R 的 BLAS/LAPACK 库快得多(参见我之前提到的基准测试,这里)。

**TLDR。**你真的不想同时使用这两种类型的并行性,小心多处理环境中的多线程部分!

“嘿,我们还在运行”——不是停止集群,或者只是认为已经停止了集群

关于性能还有一件事要提。看,我遇到过这样的问题,我几乎冻结了一台 32 核服务器。原来错误不仅仅是我生成了太多的线程,而是当我强行告诉主进程停止时,子进程没有退出(使用每个人都喜欢的组合键,CTRL + C)。由于我在 Windows 机器上工作,我天真地认为事情在 Linux 机器上应该以大致相同的方式运行我的子进程:用CTRL + C从控制台关闭主进程也应该停止子进程——只是看起来不是在 Linux 机器上。

这些子进程处于过度并行化的情况中:每个线程都在争夺 CPU (1024 个线程争夺 32 个内核!),所以他们的预计完成时间基本上是从来没有。现在,由于我没有意识到这一点,我实际上重新启动了几次计算(在不断更新代码之后),所以运行的子进程和线程比我想象的要多——这就是为什么您至少应该运行top,如果不是htop来从命令行检查您的服务器的性能。

为了确保你的过程确实停止,在你开始计算之前,你可以做一些事情。r 提供了一个名为on.exit (此处为文档)的函数,这是一个方便的小工具,当函数退出时,它会执行代码,即使是在发出CTRL + C的时候。我们可以使用它来尝试关闭我们的集群,而不管我们是否已经成功执行完当前函数:

但那是两个停止命令,不是吗?是的,但是我真的想确保我的集群被正确关闭——它最终关闭了。我还将代码包装在一个try块中,以防其中一个出错(例如,因为集群已经停止)。这两个命令是否都是必要的,我无法验证,但是尽管发出多个 stop 命令看起来很难看,但我从未遇到过这方面的问题。就像我说的,在 Windows 机器上你可能也不会有(如果你的主进程退出,子进程也会被关闭),但是一旦你完成了对集群的处理并处理了异常关闭,显式地停止集群总是一个好主意。

"多几百兆字节的内存怎么样?"—观看集群呼叫

虽然使用clusterCall代替我们之前使用的clusterEvalQ可能同样容易——以至于它们看起来是可交换的——但是这个函数有一个有趣的副作用,你可能没有意识到。为了进行模拟,我生成了一个巨大的表达式列表(占用了几百 MiB 的内存),然后将它馈送给并行的foreach循环——集群的进程然后评估这些表达式,给我最终的结果。表达式列表是在我设置集群之前生成的,所以我在确定任务中没有错误之前不会启动集群。这个生成过程完成时没有出现错误(从 base R 进程的内存使用量的大幅增加可以看出)。然后为了设置我的集群,我从使用名为.packagesforeach参数切换到使用clusterCall()来加载我需要的包,并为 MKL 和data.table设置子进程的线程数。

这一切都很好,直到我突然注意到,每个子进程的内存使用量开始从 40–50 MiB 上升到大约 6–900 MiB(准确地说,每个子进程的大小大致相同),并且这种情况一个接一个地发生:进程产生,进程#1 在几秒钟内从 40 MiB 上升到大约 670 MiB,然后进程#2 也这样做,以此类推。我花了相当多的调试时间来弄清楚到底发生了什么——我甚至没有在子进程上执行任何东西*,只有一个空的clusterCall,内存仍然增加到这个荒谬的高数量。如果您想知道,这是导致问题的一行代码:*

clusterCall(cl = parallelCluster, function () { }) # do nothing

很奇怪吧。这怎么可能呢?此外,更好的是,当我从控制台执行同样的代码行时,这个内存使用问题没有发生:内存使用保持在 40 MiB 左右。当我从控制台而不是在函数中发出命令时,我可以在集群上加载包,而不会增加几乎 1gb 的内存使用。

鉴于本节的上下文,您可能会怀疑这个问题,但是我从未看到任何迹象表明clusterCall 首先将当前函数的所有局部变量复制到子进程上。这可能是一个方便的特性,可以在其上计算函数,而不必先显式地复制变量(在clusterExport的帮助下),但这仍然很令人头疼。

所以,确保不要把太多(大)变量放入你从调用 clusterCall 的同一个函数中!相反,您可以尝试创建一个单独的函数,调用clusterCall来设置您的集群,或者确保您在函数开始时调用这个函数,但是在发出makeCluster之后(我相信所有的局部变量都会复制过来,所以如果您将一个巨大的数据帧作为参数传递给函数,它也可能会被复制到子进程)。有一个更简单的方法,尽管是,因为你可能不想用clusterCall来做设置工作(比如加载包)。

我推荐的另一个选择是用clusterEvalQ代替,特别是在初始化的时候。后者不接受函数作为第二个参数,而是接受一个表达式作为第二个参数(语法上类似),并且不会导致将局部变量复制到集群中。如果您愿意,您仍然可以使用clusterExport手动(显式)将变量移动到您的子流程中。所以用这个代替:****

尽管如此,还是有它的用处!如果您想使用当前函数中的多个局部变量,并且不想在一个clusterExport调用中显式地列出它们,这将非常方便。

有趣的事实。根据文档(以及源代码)clusterEvalQ在后台调用clusterCall。这乍一看似乎很奇怪,因为clusterEvalQ不会导致复制变量,但是我有一个答案,如果你还在阅读的话!由于clusterCall被包装在clusterEvalQ中,只有clusterEvalQ的局部变量会被复制(除了表达式本身之外,没有局部变量),所以没有额外的变量被复制到集群中。下面是clusterEvalQ的源代码(代码取自包的源代码,我只是重新格式化了它——点击侧边栏上的ClusterApply.R查看相关文件):

clusterEvalQ <- function(cl = NULL, expr) {clusterCall(cl, eval, substitute(expr), env=.GlobalEnv)
}

至此,我们已经结束了这个话题。虽然本文没有触及所有的并行化主题(比如多线程的 OpenMP 和Rcpp),但我希望它提供的信息足以帮助您避免一些狡猾的陷阱。我也希望 20 分钟的阅读时间没有把你吓跑——我很容易过度解释自己。下一次,我将尝试涵盖一些确实会带来错误消息的问题(这样它们更容易被检测到),但是这些消息可能不是很有帮助,并且可能很难调试和找到它们的根本原因——就像偶尔(即。随机得到一个Error reading from connection错误。

如果你有任何建议或更正,请在评论中添加!

以下是我在本文中涉及或触及的主题(供参考)

  • 如何用foreach在 R 中进行多重处理,为什么你会想使用它
  • 对于较小的任务,多处理的成本(称为开销)可能会超过并行处理的优势
  • 将多处理与多线程工作结合起来会意外地导致速度大幅下降
  • Microsoft R Open 是使用多线程加速计算的一个很好的选择,尤其是在不使用多重处理的时候。它可能是 base R 版本的一个很好的替代品
  • 按下CTRL + C不一定会终止集群的进程,只会终止您的主进程:确保您也能处理意外退出
  • clusterCall可以用你不想加载的数据填充你的子进程的内存,而你可能没有意识到这一点。如果您不需要您的变量在您的流程中神奇地变得可用,请使用clusterEvalQ

使用 Kompute 和 Vulkan 通过多队列操作并行处理 GPU 密集型工作负载

原文:https://towardsdatascience.com/parallelizing-heavy-gpu-workloads-via-multi-queue-operations-50a38b15a1dc?source=collection_archive---------17-----------------------

通过使用 Kompute 和 Vulkan SDK 利用多队列操作并行性,在 GPU 密集型工作负载上实现 2 倍以上的性能提升

博文视频版(Kompute 部分 13:33 开始)

GPU 已经证明对于高度并行的数据处理用例非常有用。例如,在机器学习&深度学习中发现的计算范式非常适合图形卡提供的处理架构。

然而,当涉及到多个 GPU 工作负载时,人们会认为这些工作负载会被并发处理,但事实并非如此。虽然单个 GPU 计算工作负载在众多 GPU 核心上实现了并行化,但多个工作负载是按顺序逐一运行的。那当然是直到最近显卡架构的改进,现在支持跨多个工作负载的硬件并行化。这可以通过将工作负载提交给支持并发的不同底层物理 GPU“队列系列”来实现。受益于此的机器学习实用技术包括模型并行和数据并行。

在本例中,我们将展示如何通过简单地跨两个队列系列提交多个工作负载,使这些工作负载并行运行,从而在同步示例上实现 2 倍的性能提升。

这是一项重要的优化技术,因为最近在本文档第 19 页的 NVIDIA Ampere GA10x 架构规范中概述的公告将实现3 倍的性能提升(即跨一个图形队列和两个计算队列的并发性)**,**表明这一趋势只会继续带来该领域的进一步优化改进。

我们将使用 Vulkan 和 Kompute 框架来实现这一点。更具体地说,我们将涵盖:

  • GPU 处理中“异步”和“并行”的歧义消解
  • 我们将在此基础上构建一个基本的同步示例
  • 扩展异步工作负载提交示例的步骤
  • 扩展并行多队列 GPU 处理示例的步骤

你可以在这个文件 中找到 的完整代码——关于如何使用 CMAKE 运行完整套件的说明可以在主 Kompute 库构建部分中找到。

关于 Vulkan 和 Kompute

Khronos 成员(图片由 Vincent Hindriksen 通过 StreamHPC 提供)

Vulkan SDK是由 Khronos Group 领导的一个开源项目,能够实现高度优化的跨厂商/跨平台 GPU 处理。

Kompute 是一个构建在 Vulkan SDK 之上的框架,它抽象了所需的数千行样板代码,介绍了展示 Vulkan 核心计算能力的最佳实践。Kompute 是 GPGPU 计算框架,我们将在本教程中使用它来构建核心异步和并行代码实现。

来自 Kompute Repo 的“电脑”(图片由作者提供)

异步与并行处理

在深入研究代码之前,有必要澄清两个概念,即异步工作负载提交并行工作负载处理**。**

简化的 Vulkan 建筑(图片由作者提供)

使用 Vulkan SDKGPU 队列提交并行工作负载进行处理的方式。这可以在简化的 Vulkan 架构图中看到(为简单起见,省略了管道和描述符组件)。

异步工作负载提交

异步处理包括 CPU 主机端能够在 GPU 处理工作负载的同时执行其他工作的能力。“其他工作”可以包括调用其他 C++函数,甚至向相同或其他 GPU 队列提交进一步的工作负载。当 CPU 想要检查 GPU 工作负载是否完成时,它可以使用一个 Vulkan“栅栏”,这基本上是一个信号量资源,允许 CPU 在 GPU 工作负载完成时得到通知。

值得注意的是,当多个工作负载被提交到同一个队列时,即使这些是从多个 C++线程中完成的,预期的执行顺序仍然是连续的——至少在今天的 GPU 架构中是这样。

并行工作量处理

并行工作负载处理由 GPU 同时执行两个或更多工作负载组成。更具体地说,如果您有两个 GPU 任务,每个任务需要 10 秒钟来处理,理论上两个任务的并行执行仍然需要 10 秒钟,因为它们将同时执行。

为了实现并行工作负载处理,底层 GPU 必须首先支持这一点。这一点之所以重要,是因为即使您要跨不同的 GPU 队列提交工作负载,处理仍可能由底层硬件基于其限制按顺序完成。

基本顺序处理示例

我们现在来看一下将在本文中使用的代码。代码的第一个版本将是顺序流——我们将能够将其转换成异步代码,并最终转换成并行代码。我们将基本上运行一个工作负载,在该工作负载中,我们将执行以下操作:

  1. 创建一个 Kompute 管理器来协调所有的 GPU 工作
  2. 在将用于处理数据的 CPU 主机中创建 Kompute 张量
  3. 将 Kompute 张量映射到 GPU 设备内存中
  4. 定义计算着色器,让 GPU 忙碌几个 100 毫秒
  5. 使用张量在 GPU 中运行计算着色器进行数据处理
  6. 将 Kompute 张量的结果映射回 CPU 主机内存
  7. 验证操作是否成功

为了测量时间,我们将使用标准库中的<chrono>。我们将主要使用它来计算使用std::chrono::high_resolution_clock::now()检索的开始和结束时间之间的差异,如下所示:

您可以在这个文件中找到的可运行代码,它是 Kompute 测试套件的一部分。

1.创建一个 Kompute 管理器来协调所有的 GPU 工作

首先我们必须创建 Kompute 管理器,它执行所有需要的内存管理并创建所有需要的 Vulkan 资源。默认情况下,Kompute 管理器将选择 GPU 设备 0,但是您可以传递您想要初始化的特定设备索引,如果您已经有 Vulkan 应用程序,您可以传递您的 Vulkan 资源。

2.在 CPU 主机中创建将用于处理数据的 Kompute 张量

我们现在将能够创建一组 Kompute 张量。我们首先在 CPU 主机中初始化数据,该数据由长度为 10 的零数组组成。我们将使用两个张量,因为我们将运行两个算法执行。我们将能够在最后检查这些 Kompute 张量,以确认执行已经成功。

3.将 Kompute 张量映射到 GPU 设备内存中

斯坦福 CS149 课程 2019 幻灯片

我们现在能够将 Kompute 张量的主机数据复制到 GPU 设备内存中。

这是一个重要的步骤,因为默认情况下,Kompute 张量使用仅设备可见的内存,这意味着 GPU 操作需要用 staging tensor 复制它。

Kompute 允许我们创建缓冲区和 GPU 内存块,以及通过kp::OpTensorCreate操作使用分段缓冲区执行复制。

4.定义计算着色器,让 GPU 忙碌几个 100 毫秒

我们创建的计算着色器有一个相对较大的循环来模拟“昂贵的计算”。它基本上为100000000次迭代执行一个单位加法,并将结果加到输入张量上。

5.使用张量在 GPU 中运行计算着色器进行数据处理

现在我们能够通过kp::OpAlgoBase操作提交计算着色器来执行。这基本上允许我们用各自的张量执行着色器的提交。这个初始实现同步运行执行,所以它将首先用tensorA运行着色器的执行,然后用tensorB运行同一个着色器的执行。

6.将 Kompute 张量的结果映射回 CPU 主机内存

最后,我们希望将 GPU 设备内存中的结果检索到 CPU 主机内存中,这样我们就可以从 C++中访问它。为此,我们可以使用kp::OpTensorSync操作。

7.验证操作是否成功

最后,我们可以检查两个结果kp::Tensor都包含了100000000的预期值。

扩展异步工作负载提交

在这种情况下,我们需要为异步提交扩展的步骤非常少。我们唯一需要做的就是用evalOpDefault函数代替evalOpAsyncDefault函数,然后使用evalOpAwaitDefault(<timeInNanoSecs>)等待任务完成。这基本上如下所示:

正如您所看到的,我们能够异步提交两个任务进行处理,然后使用 Await 函数等待它们完成。

值得指出的是,每次我们调用evalOpAsyncDefault时,它都会创建一个新的托管序列,而evalOpAwaitDefault只等待最近的默认序列。这意味着在上面的代码片段中,我们只等待第二个异步操作。对于我们的例子来说,这不是问题,但是如果我们现在知道的话,这可能会引入错误。正确的方法是使用显式创建的“命名序列”——我们将在下一节中这样做。

扩展并行工作负载处理

现在我们知道我们能够异步执行多个工作负载,我们能够扩展这一点,以利用 GPU 中的多个队列来实现工作负载的并行执行。

在 NVIDIA 1650 显卡上运行

为了展示一个有用的例子,我们将深入探讨如何在 NVIDIA 1650 显卡中实现这一点。您可以通过检查视频卡的设备报告(即可用的队列系列和并行处理功能)来亲自尝试。

NVIDIA 1650 中队列的概念性概述(图片由作者提供)

NVIDIA 1650 GPU 有 3 个队列系列。NVIDIA 1650 使用G进行图形处理,使用T进行传输,使用C进行计算,其familyIndex 0中的G+T+C系列有 16 个队列,familyIndex 1上的T系列有 2 个队列,familyIndex 2上的T+C系列有 8 个队列。

截至今天(2020 年 10 月),当工作跨同一系列内的多个队列提交时,NVIDIA 不支持并行处理工作负载。但是,当跨队列系列提交工作负载时,它支持并行化。这意味着图形和计算系列队列之间的工作负载可以并行化,我们将在实施中使用这一知识。

并行工作流执行的实现

到目前为止,我们已经将所有 GPU 工作负载提交到一个队列,即使用底层队列索引 0 的图形familyIndex 0。在我们使用 GPU 1650 的情况下,如果我们跨图形系列和计算系列提交工作负载,我们将能够实现并行处理。下面的图表应该为我们将要做的事情提供一个直觉。

通过多个系列队列并行执行操作(图片由作者提供)

为了做到这一点,我们需要修改三个关键的东西:

  1. 我们用相应的可用队列初始化 Kompute 管理器
  2. 我们创建了两个 Kompute 序列,每个序列都分配了相应的队列
  3. 我们在每个队列上运行操作

我们将深入研究这三点。

1.我们用相应的可用队列初始化 Kompute 管理器

当初始化一个管理器时,我们能够传递一个包含我们想要获取的队列的数组。在这种情况下,我们只获取一个图形队列和一个计算队列,但是,根据 NVIDIA 1650 的硬件规格,我们将能够请求多达 16 个图形队列(familyIndex 0)、2 个传输队列(familyIndex 1)和 8 个计算队列(familyIndex 2)。

2.我们创建了两个 Kompute 序列,每个序列都分配了相应的队列

现在,我们能够显式初始化两个托管序列,每个序列都分配到不同的队列,引用我们在上一步中传递的数组的索引。

3.我们在每个队列上运行操作

现在,我们能够运行提交到各个队列的操作。在这种情况下,并行提交两个 GPU 工作负载。

并行工作负载执行结果

运行上面提供的代码时,我们可以看到由于并行系列队列提交工作负载,执行时间提高了 2 倍。您还可以看到,如果我们从图形或计算队列提交到额外的队列,我们将不会看到任何进一步的速度提升,因为该 NVIDIA 1650 卡不支持队列内并行化。

你可以在这个文件中找到完整的代码并运行它——关于如何使用 CMAKE 运行完整套件的说明可以在主 Kompute 库中找到。

这是一个特别重要的结果,因为根据 NVIDIA 最近发布的 300x 显卡,Ampere GA10x 架构有所改进,允许同时处理两个计算工作负载。相对于上面的示例,这意味着如果我们使用一个图形队列和两个计算队列,我们可以看到 3 倍的性能提升(以及使用传输队列进行传输操作的额外性能)。

后续步骤

恭喜你,你一路走到了最后!虽然这篇文章涵盖了广泛的主题,但是也有大量的概念被浏览过。其中包括底层的 Vulkan 概念、GPU 计算基础和更高级的 Kompute 概念。幸运的是,网上有资源可以扩展你在这些方面的知识。以下是我推荐的一些进一步阅读的链接:

  • "利用 Kompute 简化移动设备中的机器学习&跨供应商 GPU&Vulkan文章,深入探讨理论和概念
  • Kompute 文档了解更多细节和更多示例
  • 移动设备中的机器学习&利用 Kompute 简化跨厂商 GPU&Vulkan
  • 用 GPU 加速你的移动应用程序使用安卓 NDK & Kompute 加速机器学习
  • GPU 使用 Godot 引擎和 Kompute 加速 ML
  • Vulkan SDK 教程深入了解底层 Vulkan 组件

用 T5(文本到文本转换转换器)解释任何问题—提供预训练模型和训练脚本

原文:https://towardsdatascience.com/paraphrase-any-question-with-t5-text-to-text-transfer-transformer-pretrained-model-and-cbb9e35f1555?source=collection_archive---------15-----------------------

来自 Pixabay 的背景图像

投入

我们节目的输入将是任何你能想到的一般性问题

**Which course should I take to get started in data Science?** 

输出

输出将是转述同一个问题的版本。转述一个问题意味着,你创造一个新的问题,用一个不同的词语选择来表达相同的意思。

**Paraphrased Questions generated from our T5 Model** ::
**0: What should I learn to become a data scientist?
1: How do I get started with data science?
2: How would you start a data science career?
3: How can I start learning data science?
4: How do you get started in data science?
5: What's the best course for data science?
6: Which course should I start with for data science?
7: What courses should I follow to get started in data science?
8: What degree should be taken by a data scientist?
9: Which course should I follow to become a Data Scientist?**

正如您所看到的,我们生成了大约 10 个问题,这些问题是对原问题的复述——“我应该学习哪门课程来开始学习数据科学?”

今天我们将看看如何从 Huggingface 的变形金刚库中训练一个 T5 模型来生成这些转述的问题。我们还将了解如何使用提供的预训练模型来生成这些转述问题。

实际使用案例

来自平面图标的图标

想象一个中学老师正在为班级准备一个测验。不是给每个学生一个固定的问题,而是他/她可以生成一个给定问题的多个变体,并分发给学生。学校也可以用这种技术用一个给定问题的几个变体来扩充他们的题库。

让我们开始吧—

资料组

来自平面图标的图标

我使用了Quora 问题对 数据集来收集所有标记为重复的问题,并准备了训练集和验证集。重复的问题有助于我们获得释义对。

我们会详细讨论你如何-

  1. 使用我的预先训练的模型为任何给定的问题生成转述问题。
  2. 使用我的训练代码和数据集在你自己的 GPU 机器上复制结果。

训练算法— T5

用扁平图标生成的图标

T5 是 Google 的一个新的 transformer 模型,它以端到端的方式进行训练,将文本作为输入,将修改后的文本作为输出。你可以在这里了解更多关于的信息。

它使用在大型文本语料库上训练的文本到文本转换器,在多个自然语言处理任务上实现了最先进的结果,如摘要、问题回答、机器翻译等。

我用原句作为输入转述(来自 Quora 问题对的重复句)句子作为输出来训练 T5。

密码

使用**“使用预训练模型”**部分中的 Google Colab 链接对此进行测试。使用给定数据训练模型的所有代码可从以下网址获得-

[## ramsrigouthamg/Paraphrase-any-question with-T5-Text-To-Text-Transfer-Transformer-

用 T5(文本到文本转换转换器)解释任何问题-提供预先训练的模型和训练脚本…

github.com](https://github.com/ramsrigouthamg/Paraphrase-any-question-with-T5-Text-To-Text-Transfer-Transformer-)

使用预先训练的模型

Google Colab notebookt5-pre trained-question-paraphraser包含以下代码。

首先,安装必要的库-

 !pip install transformers==2.8.0 

将任何问题作为输入进行推理,并查看解释的结果。

上述代码的输出是-

device  cpu**Original Question ::**
Which course should I take to get started in data science?**Paraphrased Questions ::** 
0: What should I learn to become a data scientist?
1: How do I get started with data science?
2: How would you start a data science career?
3: How can I start learning data science?
4: How do you get started in data science?
5: What's the best course for data science?
6: Which course should I start with for data science?
7: What courses should I follow to get started in data science?
8: What degree should be taken by a data scientist?
9: Which course should I follow to become a Data Scientist?

训练你自己的模型

同样,所有用于训练的训练代码和数据集都可以在前面提到的 Github repo 中获得。我们将经历我用来训练模型的步骤。

1.数据准备

首先我下载了这个链接中提到的 Quora 问题对 tsv 文件(quora _ duplicate _ questions . tsv)。

仅提取具有 is_duplicate =1 的行,因为它们是复述的疑问句。然后,我将数据分成训练集和验证集,并将它们存储在单独的 CSV 文件中。

最后,每个 CSV 文件都有两列“问题 1 ”和“问题 2 ”。“问题 2”是“问题 1”的意译版本。由于 T5 期望一个文本作为输入,我给了 "question1" 作为输入源,并要求它生成 "question2" 作为目标输出

用于生成训练和验证 CSV 文件的代码如下所示。CSV 文件位于 Github repo 中的 paraphrase_data 文件夹下。

filename = "**quora_duplicate_questions.tsv**"
import pandas as pd
question_pairs = pd.read_csv(filename, sep='\t')
question_pairs.drop(['qid1', 'qid2'], axis = 1,inplace = True)question_pairs_correct_paraphrased = question_pairs[**question_pairs['is_duplicate']==1**]
question_pairs_correct_paraphrased.drop(['id', 'is_duplicate'], axis = 1,inplace = True)from sklearn.model_selection import train_test_split
train, test = train_test_split(question_pairs_correct_paraphrased, test_size=0.1)train.to_csv('**Quora_Paraphrasing_train.csv**', index = False)
test.to_csv('**Quora_Paraphrasing_val.csv**', index = False)

2.培养

感谢 Suraj Patil 给了我们一个神奇的 Colab 笔记本来训练 T5 完成任何文本到文本的任务。我从 Colab 笔记本上借用了大部分训练代码,只更改了数据集类和训练参数。我根据 Quora 问题对数据集修改了数据集类。

Github Repo 中的培训代码为 train.py 。

你需要做的就是在任一台 GPU 机器上克隆repo,安装 requirements.txt ,运行 train.py 来训练 T5 模型。

p2.xlarge (AWS ec2)上训练该模型 2 个纪元(默认)花费了大约 20 个小时。

数据集类如下所示—

关键是我们如何向 T5 模型培训师提供我们的输入和输出。对于数据集中任何给定的问题对,我给 T5 模型输入(源)和输出(目标),如下所示

输入格式到 T5 进行训练

**paraphrase: What are the ingredients required to make a perfect cake? </s>**

输出格式到 T5 进行训练

**How do you bake a delicious cake? </s>**

就是这样!你手里有一个最先进的问题解释器。

也许这是第一个从任何给定的问题中产生转述问题的作品。

编码快乐!

使用自然语言处理的问题生成——教程

我推出了一个非常有趣的 Udemy 课程,名为“使用 NLP 生成问题”,扩展了这篇博文中讨论的一些技术。如果你想看一看,这里是链接。

祝 NLP 探索愉快,如果你喜欢它的内容,请随时在 Twitter 上找到我。

艾的幻觉

原文:https://towardsdatascience.com/pareidolia-of-ai-dba7cf44bfde?source=collection_archive---------41-----------------------

人工智能的失败之美

上传了一杯咖啡的照片和 style gan 2(art breader)对它的各种解读。截图:Merzmensch

作为预训练数据集的生存本能。

我是来保护我们的。让我们变得谨慎。幻想症。这是一个众所周知的现象,当我们看到不存在的面孔时。我们在火星上看到的面孔,我们在烤面包中看到耶稣,我们在任何地方都能看到它。嗯,它会影响我们的大脑,我们的大脑受过生物识别训练:眼睛、鼻子、嘴巴=当一切都在正确的位置时,那就是一张脸。

它起源于我们的过去——当我们漫步在树林里猎杀长毛象的时候。再一次混淆丛林和老虎,总比忽视树林间真正的捕食者要好。生存本能。

神经网络也有类似的行为。他们认识到他们所接受的训练。最好的例子是 StyleGAN2 投影,其中潜像与上传的图像并置,并检查其来源(稍后将详细介绍)。

这是一个人为和人为的幻觉的例子:

西多尼亚地区的一小部分,由 维京 1 轨道飞行器拍摄,由美国宇航局 / JPL 于 1976 年 7 月 25 日发布(来源,公共领域)//达芬奇的《蒙娜丽莎》,用谷歌深度梦境修改(来源:尼克斯敦)。

虽然我们的人眼在一些随机的岩层中看到一张脸,但早期版本的谷歌深度梦的卷积神经网络可以识别狗。到处都是。对“为什么是狗”这个问题的解释显而易见:

在 Deep Dream 的案例中,数据集来自 ImageNet,这是一个由斯坦福大学和普林斯顿大学的研究人员创建的数据库,他们建立了一个包含 1400 万张人类标记图像的数据库。但是谷歌没有使用整个数据库。相反,他们使用了 2012 年发布的 ImageNet 数据库的一个较小的子集,用于一场比赛…这个子集包含“120 个狗子类的精细分类”
(来源: FastCompany )

这是有偏神经网络的第一次可视化,在有限的数据集上进行训练。人工智能无法识别未经训练的物体,这不是它的错。这取决于我们。

失败的美妙之处

但是如果用于实验目的,这个缺陷可以成为一个优势。

您已经看到了 StyleGAN2 投影功能。

该函数的主要任务是将给定的图像与潜在空间(StyleGAN 的隐藏层,所有唯一的图像种子在被修改之前位于该层)中的种子进行比较。其中,匹配的图像可以指出深层的伪造(用于犯罪学家的图像取证)。

在我实验的某个时候,我尝试了除了外貌图片之外的其他图像。

它带来了一些令人惊讶的结果:

或者甚至是令人不安的(说到恐怖谷):

我在这个实验中使用了基于 StyleGAN2 的神经网络,在来自 FlickrDataset 的人脸上进行训练,在 1024×1024 的 FFHQ 数据集上使用 StyleGAN2。

相同的数据集在 web 应用程序art breader中实现。使用上传功能,您可以用新图像来增加潜在空间。但是它们与 StyleGAN2 训练的网络对齐,并使用投影特征以兼容的方式修改。

有时,将特定的非潜像添加到潜像空间会产生有趣的效果。在一个案例中,StyleGAN2“纠正”了一位艺术家的照片,他开玩笑地用一张纸碟遮住了自己的眼睛:

尝试有限的识别技能(这是由有限的训练造成的)可以带来迷人的结果。

它开始于我试图上传一个物体的照片。没有任何面部表情或生物特征。我的动机是检验 StyleGAN2 能够以何种方式识别和分类随机主题(而不是照片肖像)。

所以我上传了我一杯咖啡的照片。虽然是随机的。

左图:原始图像(Merzmensch 拍摄)//右图:由 ArtBreeder 上传并投射到潜在空间的这张图像

使用各种神经层(特定面部特征)的进一步修改,生成了新的肖像。如你所见,艾既不能认出这幅画,也不能模仿它的外貌风格和特征。但是结果却是独一无二的。

正如你所看到的,在第一张图像中,黑点被 AI 识别为一只眼睛——面部的其他部分也跟着识别。

只有四张脸由 StyleGAN2 驱动网络//由 Merzmensch 生成

在运动中,你可以更好地看到面部神经层之间的转换。但是你永远找不到一杯咖啡的任何痕迹。

我的系列“偶像崇拜”中的一集

实验的结果

这个实验以非常直观的方式证明了:

ML 识别模型的质量高度依赖于它被训练的数据集。这些数据集的质量取决于人工标记和准备。

在我们信任人工智能之前,我们应该让这种信任发生在我们自己身上。检查数据集及其出处,跳出框框思考(“如果”会发生什么),并意识到到 AGI 还有很长的路要走。

pareidolia——向人工智能教授艺术

原文:https://towardsdatascience.com/pareidolia-teaching-art-to-ai-d78889406bd1?source=collection_archive---------32-----------------------

Pareidolia 是我们在外星智能保护伞下的第一个人工智能艺术项目。

外星智能 ,我们探索自己教 AI 艺术的能力;让它产生一些理解的证据,然后分析和解释它的反应。我们从一个简单的“教训”开始,并计划在一个迭代的过程中逐渐发展它的内容和复杂性。交互的质量和各自的结果将取决于人工智能的技术能力,以及我们人类在与它交流时的独创性/局限性。

幻觉——看到人类是人之常情

幻视症是对观察者已知的刺激作为物体、模式或意义的不正确感知的倾向,例如在云中看到形状,在无生命物体或抽象模式中看到面孔,或在音乐中听到隐藏的信息。 维基百科

幻觉——你看到了什么?(谷歌图片搜索)

在这个项目中,我们的目标是向人工智能传达某些艺术作品是对现实世界中的物体和想法的感知或解释。作为第一类这样的物体,我们选择了最人性化的物体——人脸。

更具体地说,我们首先从展示照片中捕捉到的人工智能“真实”人脸开始。接下来,我们向它展示肖像绘画中对人脸的艺术描绘——从写实,一直到抽象表现。

然后,我们探索人工智能的“理解”:我们向它展示它以前从未见过的新肖像绘画,并要求它生成一张捕捉艺术作品中面部本质的逼真照片(是的,相反的方向)。我们很想知道它会产生什么。我们从现实主义绘画开始,但我们的意图是进一步扩展到抽象,立体,超现实主义,以及 3D 作品。最后,在真正的“Pareidolia”时尚中,我们将给予它不是人脸的物体的照片,并探索它如何将它们投影为人脸的真实照片。

我们的目标是探索一个结合点,它不仅扩展了人工智能理解和表达艺术的能力,还扩展了我们人类在与人工智能交流我们的目标并与之合作方面的局限性。

所有的魔法都是有代价的

在这种入门水平上,让人工智能艺术教学变得神奇的是,不需要向它提供什么是脸、什么是肖像画以及它们如何相互关联的精确定义和复杂解释。相反,我们只是给它(许多)两者的例子,它就不知何故地学会了。听起来很刺激?好吧,小心!所有的魔法都有代价。

在我们的例子中,这个价格源于 AI 缺乏任何关于面部、肖像或艺术的先验知识。事实上,它几乎缺乏任何关于我们、我们的历史和我们的堕胎的先验知识。也不是我们生活的世界。它所拥有的唯一信息,就是它所显示的图像中存储的内容。尤其是,它无法接触到我们在看肖像和照片时认为理所当然的许多概念和事实。

例如,脸是人体的一部分,有某些普遍的共性,如头的一般形状,眼睛,耳朵,鼻子和嘴的存在和位置。事实上,人类来自不同的性别、种族和年龄,以及一系列的基因变异——所有这些都是面部的可见属性。还有更微妙的事实,如头发和面部毛发的可变性,以及面部表情。此外,什么是人脸的“自然”方向,以及从上面看或从侧面看如何的知识。正是这种先验知识让我们人类能够毫不费力地识别和分析人脸,并区分真实的人脸和看起来像人脸的东西。

区分真脸和看起来像真脸的东西的能力

同样,也有与肖像相关的概念和事实。例如,细致入微的理解是肖像试图捕捉一张脸,但不一定像镜子那样以直接和准确的方式捕捉。相反,有内在的限制和有意的改编——使用的技术,艺术陈述和议程,执行的时间和地点,以及艺术作品的组成和设置。

这些都是我们认为理所当然的知识,对于学习照片和肖像之间的关系至关重要。人工智能无法接触到的知识。

诚然,人们可以想出复杂的方法来将这些信息传达给人工智能。例如,为图像和肖像提供标签——明确详细说明性别、种族、年龄、表情和其他面部特征(秃顶、有胡子、小胡子、金发、长鼻子、浓眉等)。然而,我们做了一个有意识的决定,不使用这些,看看我们仅仅用这些未标记的照片和肖像能走多远。我们想让我们与人工智能的对话保持简单。

来自火星的肖像和来自金星的照片

到目前为止,我们用作训练样本的图像的重要性肯定是显而易见的,因为它们封装了 AI 可以访问的所有信息。让我们仔细看看。

在理想的世界中,我们会给 AI 提供成对的图像:一张人脸的照片,以及同一个人的匹配肖像。不幸的是,这样的数据集并不存在。我们拥有的大部分肖像是在照相机发明之前的,我们拥有的大部分照片是那些觉得没有必要画肖像的人。

此外,公开的人脸照片数据集通常基于网络上的名人照片。这些照片主要偏向于年轻、白皙、好看、时尚、微笑的面孔,这些照片是从最佳的正面位置拍摄的。这与我们在肖像中发现的年龄、表情、位置和纹理的分布形成了巨大的对比(除了它们大多是白色物体)。这一点可以通过例子得到最好的说明:

画像

照片

这种看似简单的差异给我们的人工智能带来了巨大的挑战。因为这两个数据集(照片和肖像)实际上代表了人类的两种非常不同的观点。这确实对人工智能的学习、理解和输出有非常明显的(和预期的)影响。

同样,有很多方法可以尝试解决这个问题。从使用更具代表性的照片数据集(说起来容易做起来难,通常是以牺牲质量为代价),一直到创造“合成肖像”。也就是说,通过算法从照片中制造出“艺术”肖像,并将其配对使用。

然而,像以前一样,我们决定在这个阶段坚持简单,不使用合成肖像。

合成生成的肖像(【https://deepart.io/latest/】T4)

现在,我们终于完成了这个冗长的介绍,让我们看看我们的项目,以及我们实际上产生了什么。

Pareidolia 项目

我们认为这将是深刻的和有趣的艺术过程,并有我们的输出是基于肖像合成的“现实”照片,而不是相反。此外,我们不希望人工智能“简单地”在原始肖像上应用风格过滤器,并使它看起来更像照片。相反,我们希望捕捉肖像的语义,并将其重新创建为看起来像现实照片的“艺术投影”。

为了实现这一点,我们开始训练人工智能,使其能够将照片和肖像的语义与它们的风格分开,并将这些语义映射到一个共享的“面部”空间。

然后,我们探索了人工智能在这项任务中的成功程度,要求它根据从未见过的肖像生成一张新的合成照片。

我们认为这将是对“理解”的深刻展示——既包括肖像,也包括人脸。

轻度技术插曲(阅读风险自担)

尽管如上所述,我们希望输入尽可能简单和真实,但我们仍然必须应用一些简单的修改。具体来说,脸裁剪。作为人类,我们自然会被肖像中的脸所吸引。然而,从下面可以看出,在现实中——人脸只占据了肖像的一小部分。其余的是身体,mise-en-scène,主要是背景。虽然我们可能不会被它困扰,但它为缺乏任何背景和先验知识的人工智能提供了大量分散注意力的信息。所以,为了把重点放在重要的事情上,我们把两个系列的脸都剪了。

肖像——脸部只占整幅画的一小部分

肖像—裁剪过的脸

照片—裁剪的面孔

既然我们已经对输入示例进行了排序,我们必须选择与我们的目标相匹配的 AI 方法。

由于我们不想应用“简单”的过滤器,我们决定不采用风格转换的方法。我们也不想使用机器学习模型来查看源人像和目标合成照片之间的像素级相似性。因此,我们寻找对图像语义进行操作的 GAN 模型(GAN 代表生成性对抗网络——一种基于博弈论思想的机器学习技术,可以生成符合预期标准的输出)。由于我们有两个独立分布的额外约束(这意味着,我们没有成对的照片肖像来训练,而是两个独立的集合),我们用更广泛的 Cycle-GAN 家族的不同成员进行了实验。我们尝试了不同的选项和修改,最终找到了稍微修改过的版本 MUNIT (10 个纪元* 100k 次迭代)。

击鼓:结果和结束语

下面是结果!这是 3 个调色板,每个包含 24 对(每行 4 个 x 6 行)。每一对都是由左边的原始肖像和右边的合成照片组成的。

有些照片出奇的好,有些差的要命。有一点很清楚:人工智能是我们通过“名人”照片训练集强加给它的偏见的受害者。在照片的世界里,人们都是 20-30 岁,直视镜头,面带微笑,拥有完美的皮肤和直发。太老或太年轻,面部毛发,卷发,或稍微意想不到的角度——都不太好。然而,考虑到这是在没有背景或解释的情况下完成的,这是发人深省的。

每个调色板包含 24 对原始肖像和生成的“照片”

人工智能懂艺术吗?我们的绝对没有。绝对不是以人类的方式。然而,它所产生的肯定是有趣的和令人鼓舞的。一些结果似乎指出了理解上的根本差距,然而另一些结果却出人意料地好,令人兴奋。此外,当我们对这个项目进行实验时,我们提出了许多如何使它变得更好的想法。然而关键是这是否是一次值得的旅行。我们能通过这种对话——通过尝试向人工智能教授艺术——来学习关于我们世界的新见解,以及关于我们对世界的感知吗?我们计划继续探讨这个问题。

享受?看看我们的下一个项目——玫瑰色人工智能

帕累托分布和蒙特卡罗模拟

原文:https://towardsdatascience.com/pareto-distributions-and-monte-carlo-simulations-bee46113211d?source=collection_archive---------44-----------------------

用帕累托分布模拟网页浏览

帕累托分布无处不在。它也被称为 80/20 法则。举几个例子:

  • 20%的网站获得了 80%的流量。
  • 全球收入最高的 20%的人赚了 80%的收入。
  • 你 80%的时间穿 20%的衣服。

传统上,我们认为统计范围的假设分布是一个正态分布,即均值=中位数=众数的分布。

资料来源:RStudio

然而,我们在周围观察到的许多现象往往更接近帕累托分布。

来源:Jupyter 笔记本输出

在这个特定的例子中,我们可以看到一个严重右尾的分布,即大多数具有较低值的观察值(如 x 轴所定义的)倾向于图表的左侧,而少数具有较高值的观察值倾向于图表的右侧。

用蒙特卡罗模拟法模拟网页浏览

让我们以一段时间内的网页浏览量为例。这是一个曲线图,显示了 2016 年 1 月至 2020 年 8 月“地震”一词随时间的波动,来自维基媒体 Toolforge:

来源:维基媒体工具锻造

我们可以看到,在某些时段,页面浏览量会出现“峰值”——可能是在世界上某个地方正在发生地震的时候。

这正是我们所期待的——这是一个搜索词的例子,它在某些时候有更高的页面浏览量。事实上,许多网页遵循这种模式,流量或多或少遵循一种稳定的模式——伴随着突然的“峰值”。

让我们画出这个数据的直方图。

来源:Jupyter 笔记本输出

在上面的例子中,我们看到某一天的大部分页面浏览量都低于 10,000 ,但也有极少数情况超过了这个数字。

在选定的时间段内,某一天的最大页面浏览量为 31,520 。这很接近帕累托分布。

试图用传统的时间序列工具如 ARIMA 来预测页面浏览量是徒劳的。这是因为不可能提前知道特定的流量高峰将在何时出现,因为它严重依赖于外部环境,而与过去的数据无关。

一个更有意义的练习是运行模拟来预测假设帕累托分布的情况下人们可能期望看到的流量范围。

帕累托分布在 Python 中的调用如下:

numpy.random.pareto(*a*, *size=None*)

a 表示分布的形状,size 设置为10000,即从分布中产生 10000 个随机数用于蒙特卡洛模拟。

计算原始时间序列的平均值和标准偏差。

mu=np.mean(value)
sigma=np.std(value)

时间序列的均值为 5224 ,标准差为 2057

使用这些值,可以使用这些参数以及来自假设的帕累托分布的随机采样来生成蒙特卡罗模拟。

t = np.random.pareto(a, 10000) * (mu+sigma)
t

如上所述, a 的值取决于分布的形状。让我们首先将它设置为 3

以下是以百分位数表示的分布记录值:

来源:Jupyter 笔记本输出

我们可以看到 a = 3 时记录的最大值超过 35 万,远远高于时间序列记录的最大值。

如果我们设置 a = 4 会发生什么?

来源:Jupyter 笔记本

我们现在看到记录的最大值现在超过了 60,000 ,这仍然比时间序列记录的最大值高很多。

我们试试 a = 5

来源:Jupyter 笔记本输出

解释

最大页面浏览量刚刚超过 35,000,这更符合我们在原始时间序列中看到的情况。

然而,在这种情况下,我们只查看 2016 年以后的时间序列数据。许多最严重的地震实际上发生在 2016 年之前。

例如,让我们假设像 2004 年印度洋地震和海啸那样严重的地震将在今天发生——我们有理由预计对术语**“地震”**的页面浏览兴趣将比我们自 2016 年以来观察到的大得多。

如果我们假设帕累托分布有 a = 3 ,那么模型表明这个词的页面浏览量可能会超过 350,000

在这方面,蒙特卡洛模拟允许我们检查超出已记录的时间序列数据界限的情况。

地震(不幸的是)比互联网存在的时间要长得多——因此我们没有办法测量在记录最强烈地震的时候这个搜索词的页面访问量会是什么样的。

也就是说,结合对最接近的理论分布的建模进行蒙特卡罗模拟,可以允许对特定情况下时间序列的界限进行强场景分析。

结论

在本文中,您已经看到:

  • 什么是帕累托分布
  • 如何在 Python 中生成这样的分布
  • 如何将帕累托分布与蒙特卡洛模拟结合起来

非常感谢你的时间。一如既往,非常感谢任何反馈、想法或问题。请随意在评论区留下它们。

免责声明:本文是在“原样”的基础上编写的,没有任何担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。

参考

  • 机器学习掌握:概率的蒙特卡罗抽样
  • Numpy v1.14 手册:numpy.random.pareto
  • 堆栈溢出:Matplotlib —从 x 轴到点画线
  • 走向数据科学 Python 中的蒙特卡罗模拟:分析网页浏览量
  • Wikimedia Toolforge:浏览量分析

基于 Mask-RCNN 的停车位检测

原文:https://towardsdatascience.com/parking-spot-detection-using-mask-rcnn-cb2db74a0ff5?source=collection_archive---------15-----------------------

如何使用 Mask-RCNN 检测停车位的可用性?

空的/被占用的停车位

我最近在做一个项目,根据安全视图摄像头的照片来检测停车位是否可用或被占用。我的工作有局限性,我将进一步深入探讨,但一旦这些问题得到解决,这个项目可能是优化停车可用性的低成本解决方案。这个项目当然有可能简化在给定区域寻找停车位的过程,因为大多数停车场都安装了安全摄像头,这样停车场就不需要安装任何额外的设备。

让我详细说明一下我在这个项目中使用的资源。Kaggle 上有一个停车场数据集,它有足够的数据点来训练深度学习模型和 xml 文件,这些文件带有关于停车位是否被占用的注释。你可以在这里访问数据集停车场数据集。对于这个模型,我使用了最先进的对象检测和分割掩模-RCNN 模型,它表现令人惊讶,可以通过这个链接访问。

正如你所看到的,Mask-RCNN 在 COCOdataset 模型上进行预训练,在对象检测和分割方面表现出色。尽管在某些情况下,它会将汽车误分为火车和卡车。

掩模-RCNN 目标检测和分割

顺便说一下,我还尝试了 YOLO-v3,其性能相同,所以我没有进一步使用 YOLO 模型,但如果你正在寻找替代 YOLO 是一个用于对象检测的可怕模型,这里有链接。

YOLO 模型检测停车场上的汽车

首先,我使用 Mask-RCNN 模型来检测停车位上的车辆,并根据给定的停车位数量来计算空位。我们的模型不需要所有的 COCO 类,所以我将这些类限制在汽车、卡车和摩托车上。但是,在 COCOdataset 模型上预先训练的模型在检测小对象方面做得并不出色,即使我尝试调整阈值和边界框,那些被错误分类为火车的汽车也没有被检测到。这里绘制的是边界框,而不是模型的 visualize 方法提供的遮罩。

使用绘制的边界框而不是遮罩的遮罩-RCNN 模型预测

鉴于上述性能,我决定训练 COCO 模型的顶层,不仅从预训练的模型中转移知识,而且还根据我们的数据集改进预测,这样我们就有两个类来预测该位置是被占用还是空着。

该停车场数据集的约束条件是,照片仅从两个视角拍摄,这导致了训练模型的过度拟合问题,并且不允许更好地概括。第二,每个停车点的注释不完整,因此在训练期间产生异常,此外,不是照片上所有可用的停车点都被注释,这也导致模型的较差性能。我会告诉你我的意思,下面的照片只是显示了有多少停车位被标注:

并非所有的停车位都有标注

许多 xml 文件没有填充占用类:

注释文件中缺少信息

信息缺失的停车位数量可能上升至 10-15 个左右。我以为这可以手动修复,但是在运行了一些代码之后:

要修复的文件太多了,为了只训练模型的顶层,避免这些文件更容易。为了解析 xml 文件,我使用了 XML.etree.ElementTree 内置 python 包。同样值得注意的是,边界框的坐标是以一个中心点的角度给出的,所以如果我们想正确地解析和创建边界框,一些调整是必要的。

函数解析 xml 文件并提取停车场的轮廓

由于 Mask-RCNN 使用掩码来训练类,以类似于袋鼠检测文章的方式,可以在这里访问,我使用边界框来创建掩码。这篇文章实际上在理解如何使用 Mask-RCNN 模型和机器学习掌握方面帮助了我很多,一般来说,对于许多机器学习应用程序来说,这是一个很好的资源。所以,如果你还没看过的话,就去看看吧。主要的区别是,我们将检测 2 个类别,而不是一个,从而根据已占用的类别以及边界框的计算方式来创建遮罩。

函数从边界框中创建遮罩,并创建两个类来检测

至于数据集的组织,我们必须为训练和测试数据创建两个目录,每个目录包含 image 文件夹和 matching label 文件夹,其中每个 xml 文件都有相同的文件名,只是扩展名不同。而其余部分实际上遵循一般实践来训练 Mask-RCNN 的顶层。你可以在 Matterport GitHub 上查看不同的样本代码。

我们必须创建一个类 ParkingLot,它将加载数据集,通过解析 xml 注释文件提取边界框的轮廓,根据提取的轮廓创建遮罩,我们需要一个图像引用函数,它将返回注释 xml 文件的路径。

创建 ParkingLot 类

然后,我们需要根据我们希望模型接受训练的类来指定配置类,加载训练和测试数据集,使用“训练”模式加载模型并开始训练。

ParkingConfig 类

该模型将在每个时期后保存在 logs 文件夹中,这样一旦训练完成,您就可以继续加载该模型以评估其性能。使用 Mask-RCNN 的方法是创建新的配置类来限制我们预测的范围

预测配置类

使用“推理”模式加载模型,从日志文件夹加载模型:

由于 Mask-RCNN 可视化了检测到的对象及其类的遮罩,我们将使用此函数来绘制边界框:

函数绘制检测到的对象的边界框

因此,如果我们加载任何随机图像,检测可用和已占用的停车位,使用我们的函数来绘制它们,结果将是这样:

检测到可用停车位

绿色方框是可用的停车位,蓝色边框是已占用的停车位。看起来模型性能还不错,虽然还是检测不到小型车/停车点。数据集中有意忽略了停在人行道旁的汽车,以便模型在训练时不会将这些汽车考虑在内。这是使用 Mask-RCNN 的 visualize 方法得到的结果:

Mask-RCNN 检测可用停车位

鉴于这一结果,似乎该模型的性能真的很好。但是在我们的数据集中,我们只有停车场的两个角度,因为我只训练顶级模特,所以我只使用了数据集的一部分。那么,为什么不看看停车场的另一张照片,上面有一个类似的摄像头,但不是这个数据集的一部分。我们的模型会有多好?

哇!这太糟糕了。很明显,该模型过度适合我们的停车场数据集,这意味着它在相同的数据集上表现良好,我没有说训练,因为训练和测试照片实际上是停车场中不同汽车的相同照片,虽然技术上没有泄漏测试数据,但在某种意义上它们是相同的。开箱即用的预训练 Mask-RCNN 将在检测车辆方面表现得更好。

考虑到这些结论和我前面提到的局限性,下一步可以采取什么措施来改进模型或向前发展呢?嗯,我们可以使用整套数据从头开始训练模型,看看它的表现如何,尝试调整检测阈值。我不妨试着这样做,也许这可以成为这篇文章的第二部分?但理想情况下,更多变化的数据集是必不可少的,完整的注释是创建准确的停车点检测模型的基础。此外,为了建立不仅准确而且鲁棒的检测模型,我认为考虑正在移动但尚未停放的车辆,即未经授权停放的车辆非常重要。这些可能是未来需要进一步研究的问题。

感谢您花时间阅读我的帖子!

使用 Python 在几分钟内解析数千份股票推荐!

原文:https://towardsdatascience.com/parse-thousands-of-stock-recommendations-in-minutes-with-python-6e3e562f156d?source=collection_archive---------12-----------------------

了解如何在不到 3 分钟的时间内解析顶级分析师的数千条建议!

如果你和我一样,你可能已经想了很多次什么股票是最热门的,分析师如何轻松地发现这些股票。我会经常在雅虎财经页面上随意查找一些股票,看看它们的评级是否很高。我也知道必须有一个更好的方法来找到这些随机股票,所以我用不到 40 行代码创建了这个简单的解析器。

照片由杰米街在 Unsplash

在我进入编码方面之前,我想快速了解一下雅虎财经页面上的这些推荐内容和位置。如果你转到页面并输入一只股票,你会看到类似我下面的图片。该页面包括股票表现和关键统计数据的交互式图表,如市盈率、每股收益、Beta 值、股息信息等。你甚至可以在左下角看到这只股票目前是被低估了,还是被高估了,或者处于合理的价值。然而,这不是建议的位置。

苹果的雅虎财经页面

如果你继续向下滚动,页面右侧会出现一个类似下图的图表,概述了分析师在过去几个月对特定股票的建议。

雅虎财经股票分析师推荐图

股票分析师将股票分为 1-5 级,1 级表示强烈买入,5 级表示强烈卖出。推荐的平均值是底部的推荐评级(苹果的评级为 2)。我的算法解析给定列表中每只股票的值,然后将数据下载到 CSV 文件中。下面的 GitHub 要点包含了所有的代码。

解析算法的所有代码。

首先,我们必须导入依赖项,然后定义两个变量。跑马灯列表目前设置为包含标准普尔 500 的所有跑马灯符号,但可以根据您的喜好进行更改。如果您要增加代码列表,我建议取消注释第 31 行中的“time.sleep(0.5)”代码。建议变量被设置为一个空列表,这样我们就可以用它来存储我们从即将到来的 for 循环中收集的值。

for 循环实际上包含解析算法,该算法允许 Python 访问每只股票的雅虎财经页面,并收集其各自的推荐评级。任何没有有效评级值的公司都将以值 6 保存到列表中。

最后,将创建一个熊猫数据框架,其中包含每个股票及其推荐。然后,数据帧将作为 CSV 文件下载到您的计算机上。

我希望这个程序将来会对你有用。非常感谢您的阅读!

免责声明:本文材料纯属教育性质,不应作为专业投资建议。自行决定投资。

参考文献:

[## 解析雅虎财经

感谢贡献一个堆栈溢出的答案!请务必回答问题。提供详细信息并分享…

stackoverflow.com](https://stackoverflow.com/a/42237860/11915680)

如果你喜欢这篇文章,可以看看下面我写的其他一些 Python for Finance 文章!

[## 用 Python 进行股票新闻情绪分析!

对财经新闻进行秒级情感分析!

towardsdatascience.com](/stock-news-sentiment-analysis-with-python-193d4b4378d4) [## 用 Python 制作股票筛选程序!

学习如何用 Python 制作一个基于 Mark Minervini 的趋势模板的强大的股票筛选工具。

towardsdatascience.com](/making-a-stock-screener-with-python-4f591b198261) [## 在 3 分钟内创建一个财务 Web 应用程序!

了解如何使用 Python 中的 Streamlit 创建技术分析应用程序!

towardsdatascience.com](/creating-a-finance-web-app-in-3-minutes-8273d56a39f8)

几秒钟内解析 TradingView 股票推荐!

原文:https://towardsdatascience.com/parse-tradingview-stock-recommendations-in-seconds-1f4501303b21?source=collection_archive---------20-----------------------

了解如何使用 Python 解析任意时间间隔的实时建议!

在我之前的一篇文章中,我们讨论了如何解析来自雅虎财经的顶级分析师对任何股票的建议。虽然他们提供了股票未来走势的验证,但他们每月只更新一次,并且没有提供任何关于评级背后的理由的信息。

幸运的是,从那以后,我偶然发现了一个很棒的网站 TradingView 。如果你不熟悉这个网站,他们提供的一个功能是短至 1 分钟或长达 1 个月的实时推荐。这些建议纯粹基于技术指标,包括移动平均线、振荡指标和枢轴,你可以直接在页面上看到计算结果!

因此,我没有每次需要推荐时都访问网站,而是用不到 50 行代码创建了这个简单的解析器。

照片由尼克冲在 Unsplash 上拍摄

TradingView 简介

在我进入编码方面之前,我想快速介绍一下 TradingView 上的这些推荐内容和位置。如果你转到这个页面,你会看到一些类似于我下面的图片。该页面包括关键统计数据,如市盈率、每股收益、市值、股息信息等。你甚至可以点击概览来获得一个全面的比率表,以及一个交互式图表和最近的新闻。然而,这不是建议的位置。

苹果交易视图页面顶部

如果你继续向下滚动技术面页面,会有多个图表,如下图所示,列出了信号背后的建议和统计数据。

TradingView 推荐图表(我们将收集的内容)

交易视图技术指标统计

建议范围从强买到强卖,正如你在第二张图中看到的,它们完全依赖于技术指标信号。我们将建立的算法将很快分析买入信号、中性信号、卖出信号的数量,以及总体建议。下面的 GitHub gist 包含了所有的代码!

使用 Python 抓取 TradingView

解析算法的所有代码。

设置

如果您没有安装 Selenium 或 Pandas ,您可以访问它们各自的链接,并使用终端中的 pip 下载它们!我们还需要一个 chromedriver(模拟的 chrome 浏览器 Selenium 控件),要使用 Python 下载它,你可以使用 PyPi 中的 webdriver-manager 包。

此外,只要安装了必要的依赖项,就可以使用任何支持 Python 的 IDE 或文本编辑器。我个人会推荐通过 Anaconda 下载 Visual Studio 代码或者 Spyder。

让我们进入代码

现在所有的东西都应该已经安装在你的机器上了,你也知道我们要抓取什么了,让我们开始写代码吧!

首先,我们必须导入程序其余部分所需的依赖项。在这种情况下,我们将需要内置的时间模块、Pandas 和 Selenium。

时间模块将允许我们让程序休眠几秒钟,以便模拟的浏览器可以完全加载。熊猫将允许我们用我们收集的数据创建一个数据框架。最后,我们将需要 selenium,这样我们就可以创建/控制浏览器窗口并抓取 JavaScript 呈现的信息。

接下来,我们可以创建两个变量,一个用于 ticker,另一个用于我们特别抓取的区间。间隔可以是我在下面代码栏中包含的任何一个。

#===================================================================
# Intervals: 
# 1m for 1 minute
# 15m for 15 minutes
# 1h for 1 hour
# 4h for 4 hours
# 1D for 1 day
# 1W for 1 week
# 1M for 1 month
# ==================================================================

在我们包含了导入和参数之后,我们可以设置 chromedriver 了。Options 类将允许我们添加 headless 这样的参数来定制模拟的浏览器。添加 headless 告诉浏览器在每次运行程序时不要弹出。我们可以将可执行路径设置为您之前下载 chromedriver 的路径。在这种情况下,我将它直接下载到我的目录中,但您不必这样做。

我们可以在一个 try/except 块中添加我们的抓取脚本来捕捉程序中断时的错误。首先,我们必须使用 webdriver.get(URL)打开浏览器,刷新以正确加载页面的各个方面,然后添加 time.sleep(1)使程序慢一秒钟,直到浏览器完全渲染完毕。

使用。通过 selenium.webdriver 中的 find_by_class_name 方法,我们可以精确定位我们想要清除的部分。例如,只有建议具有以下类“speedometerSignal-pyzN-tL”我们可以通过 Chrome DevTools 中的 inspect 元素来检索这些类名。打开 DevTools,你可以右击你想解析的部分,然后按“inspect ”,得到类似下图的结果!

Chrome 开发工具

我们可以使用方法检索“Buy”。get_attribute('innerHTML '),它将存储 HTML 标记内的文本。

同样,我们可以检索买入、中性和卖出信号的数量,方法是找到所有这些信号之间相似的类名,然后使用方法。按类名查找元素。因为这次我们调用的是元素,而不是元素,所以这个方法将返回一个包含我们指定的类名的 HTML 标签列表。

最后,我们可以将所有信号附加到一个列表中,并使用。from_records 方法,我们可以将数据元组和列列表转换成 DataFrame。最后,我们可以通过为 ticker 添加一列,将该列设置为索引,并为我们的最终产品转置(旋转)数据帧来清理它。

程序输出

现在,在几秒钟内,您应该会得到与上图类似的输出。我希望这个算法将来对你有用。非常感谢您的阅读!

免责声明:本文材料纯属教育性质,不应作为专业投资建议。自行决定投资。

如果你喜欢这篇文章,可以看看下面我写的其他一些 Python for Finance 文章!

[## 使用 Python 在几分钟内解析数千份股票推荐!

了解如何在不到 3 分钟的时间内解析顶级分析师的数千条建议!

towardsdatascience.com](/parse-thousands-of-stock-recommendations-in-minutes-with-python-6e3e562f156d) [## 用 Python 制作股票筛选程序!

学习如何用 Python 制作一个基于 Mark Minervini 的趋势模板的强大的股票筛选工具。

towardsdatascience.com](/making-a-stock-screener-with-python-4f591b198261) [## 在 3 分钟内创建一个财务 Web 应用程序!

了解如何使用 Python 中的 Streamlit 创建技术分析应用程序!

towardsdatascience.com](/creating-a-finance-web-app-in-3-minutes-8273d56a39f8)

用 Python 解析 XML 数据

原文:https://towardsdatascience.com/parsing-xml-data-in-python-da26288280e1?source=collection_archive---------3-----------------------

在熊猫数据框架中存储 XML 数据

来源

可扩展标记语言(XML)是一种以人类和机器可读的格式编码数据的标记语言。XML 在各种程序中用于构造、存储和传输数据。Python 包含几个处理 XML 数据的接口。在本帖中,我们将讨论如何使用 python“xml”库中的“ElementTree”模块来解析 XML 数据并将数据存储在 Pandas 数据框中。

我们开始吧!

出于我们的目的,我们将使用一个样本“xml”文件,“books.xml”,它可以在这里找到。该文件包含各种书籍的信息,如书名、作者姓名和价格。

首先,让我们从 python“XML”库中的“ElementTree”模块导入“parse ”:

from xml.etree.ElementTree import parse

现在,让我们看看“books.xml”中的文件标签:

我们可以通过将文件名传递给“parse()”方法来定义一个已解析的“XML”文档对象:

document = parse('books.xml')

如果我们打印对象,我们会看到在指定的内存地址有一个“ElementTree”对象:

print(document)

让我们使用内置的“dir()”方法来看看该对象可用的方法和属性:

print(dir(document))

让我们使用方法“iterfind()”来返回一个生成器,我们可以在“for-loop”中对其进行迭代。我们需要在“iterfind()”方法中指定一个路径参数。让我们选择“图书”路径:

for item in document.iterfind(‘book’):print(item)

我们看到,我们有几个“元素簿”对象存储在不同的内存地址。我们可以使用“findtext()”方法从这些对象中提取信息。让我们提取“作者”标签中的信息:

for item in document.iterfind('book'):print(item.findtext('author'))

我们还可以提取标题:

for item in document.iterfind('book'):print(item.findtext('title'))

让我们看看价格:

for item in document.iterfind('book'):print(item.findtext('price'))

接下来,我们可以初始化用来存储这些值的列表:

author = []
title = []
price = []

在 for 循环中,我们可以追加值:

for item in document.iterfind('book'):author.append(item.findtext('author'))title.append(item.findtext('title'))price.append(item.findtext('price'))

然后,我们可以将这些列表存储在一个数据框中。让我们首先导入熊猫库:

import pandas as pd 

接下来,让我们定义一个包含每本书的“标题”、“作者”和“价格”的数据框:

df = pd.DataFrame({'title': title, 'author':author, 'price':price})

接下来,让我们打印结果数据框:

print(df)

我们还可以将“流派”、“发布日期”和“描述”添加到数据框中:

genre = []
description = []
publish_date = []for item in document.iterfind('book'):...genre.append(item.findtext('genre'))description.append(item.findtext('description'))publish_date.append(item.findtext('publish_date'))

既然我们在数据框中有了所有的信息,我们可以做一些事情,例如将“价格”字符串转换为“浮点型”,并计算“价格”列的平均值:

df['price'] = df['price'].astype(float)
print("Mean price: ", df['price'].mean())

让我们也将“publish_date”转换为“datetime”对象,并提取年、月和日的值:

df['publish_date'] = pd.to_datetime(df['publish_date'])
df['year'] = df['publish_date'].dt.year
df['month'] = df['publish_date'].dt.month
df['day'] = df['publish_date'].dt.day
print(df.head())

我们还可以使用 collections 模块中的“Counter()”方法来查看作者和流派的分布情况:

from collections import Counter
print(Counter(df['author']))
print(Counter(df['genre']))

我就讲到这里,但是您可以随意使用数据并自己编码。

结论

总之,在这篇文章中,我们讨论了如何使用 python 中的“xml”库解析 XML 数据。我们展示了如何使用“iterfind()”方法来定义一个生成器对象,我们可以在“for-loop”中迭代该对象。我们还展示了如何使用“findtext()”方法访问元素标记信息。然后,我们将 XML 信息存储在用于定义 Pandas 数据框的列表中。我希望你觉得这篇文章有用/有趣。这篇文章的数据和代码可以在 GitHub 上找到。感谢您的阅读!

第 1 部分:用 Python 定义和计时 API 函数

原文:https://towardsdatascience.com/part-1-defining-and-timing-an-api-function-with-python-b0849775e961?source=collection_archive---------28-----------------------

Python 中并发性的图形化探索

探索 Python 中的并发性以加速从远程 API 检索数据的系列文章。

问题是

使用 API 时,大部分时间都花在等待响应上。当从外部服务大量收集信息时,这会导致大量时间浪费。本文探索了如何使用 Python 的多处理线程异步特性从顺序请求转变为并发请求。

介绍

在之前的文章中,我们编写了一个简单的函数,它可以处理单个查询返回的问题数量的吉拉 API 限制。这解决了问题,但即使只有几千个结果,检索所有问题的时间也可能会在几分钟内完成。

一个 JQL 查询返回 1334 个问题,每个请求 50 个问题(27 个请求),耗时 31 秒。 使用并发通过 改变 7 行代码 ,我们可以将此减少到 2.5 秒。

为什么?

使用 Jupyter 内置的%time魔法的一个快速简介显示了为什么有这么大的改进空间。

CPU times: user 672 ms, sys: 125 ms, **total: 797 ms**
Wall time: **31.4 s**

在 31.4 秒的运行时间中,顺序执行请求只占用了 797 毫秒的 CPU 时间。所以在这 31 秒中,**多 97%的时间都花在了* 等待 的网络呼叫上。*

提高性能

本质上有两类性能问题:

  1. 我一直在等待网络/磁盘/数据库/其他进程做一些事情,同时也想用 CPU 做一些有用的事情。 Python 解决方案:线程化还是异步化。
  2. 我正在做一些计算量很大的事情,希望尽可能使用所有的 CPU / GPU 时间。 Python 解决方案:多重处理或降至 c 语言

如上面的%time示例所示,API 调用牢牢地属于第一类。这是需要记住的重要一点:

我们 难道 想方设法让 各自的要求走得更快。

改为 我们试图将 【等待并行】 所以 整套要求 完成得更快。

由于我们的 CPU 做的工作很少,为了让单个请求运行得更快,我们需要查看网络层并升级连接。相反,我们可以通过分批启动请求并组合结果来加快整个请求集的速度。

方法

在本系列中,我们将从最慢的情况开始,即顺序请求,然后尝试三种加快速度的方法:

  1. ***序贯,*我们的基础案例参考点。
  2. ***多重处理,***multiprocessing.Pool()**多重处理并不完全适合这个问题,但仍然提供了很大的改进,这是一个有趣的比较。
  3. ***穿线,***concurrent.futures.ThreadPoolExecutor()**
  4. ***异步,***asyncio.gather()** 使用asyncawait以及httpx模块来支持异步 HTTP 请求。

注意:本系列中的计时代表了测试设置中每种方法的平均值,而不是严格意义上的基准。我们对绝对性能的技术之间的比较更感兴趣

我们使用吉拉 API 作为示例,但是这些解决方案可以很容易地扩展到其他用例,其中您的应用程序花费大量时间等待其他计算机/网络/磁盘/进程做一些工作并返回结果。

在这个系列中,我们将讨论两个函数。

  1. **jira_query()** 接受一个吉拉 URL,JQL 查询字符串,一个指示要检索结果的“页面”的整数。
  2. 一个函数,给定一个 JQL 查询,计算出检索所有结果需要多少个请求,并使用**jira_query()** 将所有结果以及相关的计时数据收集到一个列表中。在这里,我们将试验不同的并发方法(在每一节中显示)。

jira_query()

函数在给定起始页(查询号)、URL、JQL 查询字符串和要检索的结果数的情况下,检索吉拉问题列表。

侧边栏:用 perf _ counter _ ns() 函数计时在整个系列中,我们将使用 *time.perf_counter_ns()* 函数来记录开始和结束时间。这将从系统相关的参考时间返回以纳秒为单位的当前时间。来自文档:

返回值的参考点是未定义的,因此只有连续调用的结果之差才是有效的。

因此,我们不能跨系统比较时间,或者系统重启,但是即使请求发生在不同的进程/线程上,我们 也可以 比较相对的开始和结束时间,精确度很高。这有助于可视化不同并发模块中发生的事情。

顺序请求

下面的函数使用jira_query()建立一个结果列表,给出一个吉拉 URL、JQL 查询(例如Project = CAE ORDER BY key Asc)和每个请求返回的结果数。

按顺序从 JQL 查询结果集中检索所有问题。

调用这个函数会返回一个由jira_query()返回的字典列表。通常我们会对实际产生的问题感兴趣,但这里我们更感兴趣的是关于检索了多少个问题以及花费了多长时间的元数据,因此实际的问题列表嵌套在issue_list键中。

调用顺序版本,将结果加载到数据帧中进行显示和绘图。

产生的数据帧显示了相对于**t_0** (第一个请求开始的时间)的开始和结束时间。如您所见,我们最终收到 27 个请求,检索 1334 个问题,一次最多 50 个。

绘制结果真正说明了顺序行为。请记住,在每个蓝条期间,CPU 仅在大约 2–3%的时间内工作。剩下的时间用来等待网络请求返回。

检索 1334 个问题,每批 50 个,有连续请求。总时间为 31.4 秒,平均请求时间为 1.16 秒。

在下一节中,我们保持jira_query()不变,但是使用multiprocessing.Pool()来调整协调功能,这样可以大大加快速度。

系列地图

  • 第 1 部分:在 Python 中定义和定时一个 API 函数(你在这里)
  • 第 2 部分:用 Python 多重处理 API 请求
  • 第 3 部分:用 Python 线程化 API 请求
  • 第 4 部分:使用 Python 和 httpx 的异步 API 请求
  • 第 5 部分:API 请求时序比较——顺序、多处理、线程和异步

第一部分:情节性元学习和大脑

原文:https://towardsdatascience.com/part-1-episodic-meta-rl-and-the-brain-909b9bccfc29?source=collection_archive---------41-----------------------

实践教程

弥合机器学习和神经科学之间的差距

照片由摩根·豪斯尔在 Unsplash 上拍摄

这是我硕士学位论文系列博文的第一部分。它假设了一些神经科学和强化学习的初步知识,但不用担心,如果你有任何问题,我会在评论区。先简单介绍一下我:我获得了伦敦大学金史密斯学院的计算认知神经科学(CCN)硕士学位。因为我来自计算机科学/机器学习背景,所以我决定从事这两个领域交叉的研究项目。我很大程度上受到了 DeepMind 神经科学团队在meta-RL【20,21】上所做的工作以及萨姆·里特的博士论文【22】的启发,这篇文章在很大程度上是基于这些论文。这实际上是我决定去 CCN 攻读硕士学位的主要原因之一。这让我觉得,如果一个人想成为人工智能领域的主要研究人员,就有必要了解大脑。这篇文章讨论了情景元学习和大脑的关系,试图弥合机器学习和神经科学之间的差距。

动机

近年来,深度强化学习(RL)一直处于人工智能(AI)研究的前沿,在一系列不同的领域取得了突破[1,2,3]。这导致认知科学家转向人工智能的发展,并询问它是否能给我们任何关于人类认知机制的见解[21];考虑到 RL 最初的灵感来源于动物条件反射的心理学研究[4,5]。以伊凡·巴甫洛夫的开创性工作为例。在他的实验中,狗开始对蜂鸣器的声音垂涎三尺,将它与食物联系起来。因此,他们能够在实际观察之前就预测到奖励。使用这种预测信号,人们可以训练狗或任何动物来执行特定的任务。类似地,RL 算法可以通过正负奖励来指导人工智能体执行一组使累积长期奖励最大化的动作。

然而,deep-RL 的一个主要缺点是其样本效率低[21],这自动使其失去了作为生物学习的合理模型的资格。换句话说,为了达到适当的专业水平,一个人工智能体所需要的经验比人类所需要的要多几个数量级。为了解决这个问题,Botvinick 等人(2019 年)确定了导致 deep-RL 缓慢的两个主要原因;这些是递增的参数调整,从弱感应偏置开始。前者是为了避免灾难性的推断,而后者允许神经网络适应广泛的问题。考虑到这一点,他们表明,这两个因素都可以通过使用情景记忆和学习任务分配的元学习来缓解。他们还指出,这两种解决方案都被证明对神经科学和心理学有进一步的影响。

与生物学的关系

RL 和纹状体多巴胺系统

首先,让我们回溯一下,看看传统的 RL 算法为神经科学提供了什么。据观察,中脑多巴胺神经元的放电特性驱动纹状体中的突触可塑性,以巩固经验行为和奖励之间的联系[6]。RL 的研究后来引导神经科学家发展了多巴胺能功能的基于奖励的学习理论。具体来说,多巴胺释放编码了一个“惊喜”指数,反映了由时间差(TD) 学习算法预测的奖励预测误差(RPE)信号,或者换句话说,预期和实际奖励之间的差异【7】。对非人灵长类动物、人类和啮齿类动物的进一步研究集中在一个经典模型上,在该模型中,突触前和突触后神经元的同步放电在多巴胺存在时导致更强的突触连接,而在多巴胺不存在时导致更弱的连接[8]。换句话说,导致 RPE 信号增加的神经元放电通过所谓的“三因素规则”得到加强[9]。

Meta-RL 和前额叶皮层

然而,这一经典模型受到了来自前额叶皮层(PFC)的一系列发现的挑战。已经表明,PFC 的扇区对 RL 的基本量进行编码,例如动作和状态的期望值[10,11],以及奖励和动作的近期历史[12,13]。这表明 PFC 实现了基于奖励的学习机制,类似于以前归因于基于多巴胺的 RL 的机制。因此,一个问题自然产生了:这两个系统之间的关系是什么?Wang 等人(2018)通过提出一种新的理论解决了这一难题,在该理论中,PFC 和基于多巴胺的 RL 是两个独立的 RL 系统,实现了不同形式的学习。具体来说,他们表明 PFC 通过利用任务结构的表示来执行基于模型的 RL,而不是基于由多巴胺突触学习驱动的直接刺激-反应关联的无模型 RL。在这个理论中,前额叶网络中的突触权重是由基于多巴胺的 RL 在一系列相关任务中形成的。因此,无模型 RL 产生了能够快速适应新环境的第二种独立的基于模型的 RL,并且被称为“meta-RL”。Wang 等人(2018)通过大量模拟证明,meta-RL 可以解释大范围的行为和神经生理学发现,这些发现为基于多巴胺的标准模型带来了困难。

情景学习和海马体

Ritter 等人(2018)指出,虽然王等人(2018)提出的元强化学习框架提供了增量学习的完整描述,但它没有考虑情景学习过程。他们指出,利用过去的相关经验来制定新的决策是任何智能生物的一个基本特征。因此,代理人还必须能够将过去决策的结果提取到记忆中,并长时间存储,并且能够在以后遇到类似情况时检索相关结果,以评估未来行动的价值。最近的研究表明,在分析人类行为和 fMRI 数据时,考虑与海马相关的情景学习,比只考虑之前讨论的增量学习算法更符合模型[14]。除此之外,meta-RL 代理已被证明遭受灾难性遗忘[15];这意味着它必须重新学习以前掌握的策略,而不是利用从过去的经验中获得的知识。这些观察导致对利用情景记忆的计算模型的兴趣增加,并证明了情景学习过程在决策中的重要性[16]。受海马体相关功能属性的启发,Ritter 等人(2018)设计了扩展架构,使其包括模式完成、模式分离和皮层活动模式恢复等功能。这意味着,当代理人遇到一个类似于它以前见过的情境时,记忆应该被提取和恢复,而不完全干扰其工作记忆的当前状态。

作为计算模型的情景元强化学习

继 Wang 等人(2018)的工作之后,meta-RL 模型将 PFC 及其连接的皮质下结构(即基底神经节和丘脑核)概念化为形成同质的递归神经网络(RNN),该网络遵循对这组区域进行建模的新兴传统,抽象出许多神经生理学和解剖学细节[17]。它使用一种演员-评论家算法进行训练,这反映了基于多巴胺的学习系统。该网络在每个时间步接收感知数据的编码版本作为输入,以及表示在前一时间步它已经采取的奖励和行动的信号。RNN 学会将观察、奖励和行动的历史提取到它的隐藏状态中,这可以被视为一种工作记忆的形式,同时在一系列结构上相关的任务上进行训练。Ritter 等人(2018 年)扩展了这种架构,将非参数情景记忆作为可微分神经字典来实施[23]。它将工作记忆状态(即 RNN 隐藏状态)与作为密钥嵌入的感知上下文配对存储。当遇到类似的上下文时,通过使用一些学习到的门控机制,这可以稍后用于检索和恢复存储器激活到当前工作存储器中。这个模型与在神经科学研究中观察到的一致;检索情景记忆会触发一种活动模式,类似于最初在支持工作记忆的回路中经历的活动模式[18]。该模型中采用的恢复方法在功能上类似于 PFC 中运行的门控机制[19]。总之,当以最大化特定回报函数为目标,在包含情节和增量结构的任务分布上进行训练时,情节 meta-RL 模型能够提供对无模型和基于模型的策略的统一描述。

下一步是什么

在下面的文章中,我将使用这个模型来重现用于分离无模型系统和基于模型系统的情景(或上下文)两步任务的行为结果。同时,你可以在这里找到我的实现。

参考

1 Mnih,v .,Kavukcuoglu,k .,Silver,d .,鲁苏,a .,Veness,j .,Bellemare,M. G .,Graves,a .,Riedmiller,m .,Fidjeland,A. K .,Ostrovski,g .,Petersen,s .,Beattie,c .,Sadik,a .,Antonoglou,I .,King,h .,Kumaran,d .,Wierstra,d .,Legg,s .,Hassabis,D. (2015 年)。通过深度强化学习实现人类水平的控制。自然,518(7540):529–533。

[2] Silver,d .、Huang,a .、C. J .、Guez,a .、Sifre,l .、van den Driessche,g .、Schrittwieser,j .、Antonoglou,I .、Panneershelvam,v .、Lanctot,m .、Dieleman,s .、Grewe,d .、Nham,j .、Kalchbrenner,n .、Sutskever,I .、Lillicrap,t .、Leach,m .、Kavukcuoglu,k .、Graepel,t .和 Hassabis,D. (2016 年用深度神经网络和树搜索掌握围棋。自然,529:484–503。

[3] Vinyals,o .、Babuschkin,I .、Czarnecki,w .、Mathieu,m .、Dudzik,a .、Chung,j .、Choi,d .、Powell,r .、Ewalds,t .、p .、Oh,j .、Horgan,d .、Kroiss,m .、Danihelka,I .、Huang,a .、Sifre,l .、Cai,t .、Agapiou,j .、Jaderberg,m .和 Silver,D. (2019)。星际争霸 2 中使用多智能体强化学习的特级大师级别。自然,575。

[4]巴甫洛夫,I. P. (1927 年)。条件反射:大脑皮层生理活动的研究。牛津大学出版社。

[5]雷斯科拉和瓦格纳(1972 年)。巴甫洛夫条件作用理论:加固和非加固有效性的变化,第 2 卷。

[6]舒尔茨、达扬和蒙塔古(1997 年)。预测和奖励的神经基础。科学,275(5306):1593–1599。

[7]萨顿和巴尔托(1998 年)。强化学习:导论。麻省理工学院出版社,美国马萨诸塞州剑桥。

[8]n . Daw 和 Tobler,P. (2014 年)。通过强化学习的价值:多巴胺和强化学习的基础。神经经济学:决策和大脑,283-298 页。

[9]格里姆彻,P. W. (2011 年)。理解多巴胺和强化学习:多巴胺奖励预测误差假说。美国国家科学院院刊,108 期(增刊 3):15647–15654。

[10]h .普拉斯曼、j .奥多尔蒂和 a .兰格尔(2007 年)。眶额皮层编码日常经济交易中的支付意愿。神经科学杂志,27(37):9984–9988。

[11]Padoa Schioppa c .和 Assad j .(2006 年)。眶额皮层神经元编码经济价值。自然 441,223–226。《自然》, 441:223–6。

[12] Seo,m .,Lee,e .和 Averbeck,B. (2012 年)。额叶-纹状体回路中的动作选择和动作价值。神经元,74:947–60。

[13] Tsutsui,K.-I .,Grabenhorst,f .,Kobayashi,s .,和 Schultz,W. (2016 年)。前额叶皮层神经元中经济对象估价的动态代码。自然通讯,7:12554。

[14]博恩施泰因、卡瓦、肖哈米和道(2017 年)。对过去选择的回忆会使人类对奖励产生偏见。bioRxiv。

[15] Ritter,s .,Wang,J. X .,Kurth-Nelson,z .,Jayakumar,S. M .,Blundell,c .,Pascanu,r .,Botvinick,M. M. (2018 年)。经历过,做过:元学习与情景回忆。在 ICML。

[16] Gershman,S. J .和 Daw,N. D. (2017 年)。人类和动物的强化学习和情景记忆:一个整合框架。心理学年度评论,68(1):101–128。PMID: 27618944。

[17]宋海峰,杨广瑞,王晓军(2016)。用于认知和价值任务的递归神经网络的基于奖励的训练。bioRxiv。

[18] Xiao,x .,Dong,q .,Gao,j .,Men,w .,Poldrack,R. A .,和薛,G. (2017 年)。情景记忆提取过程中的变形神经模式恢复。神经科学杂志,37(11):2986–2998。

[19]c .查塔姆和 d .巴德雷(2015 年)。工作记忆的多重门。行为科学最新观点,1:23–31。

[20] Wang,J. X .,Kurth-Nelson,z .,Kumaran,d .,Tirumala,d .,Soyer,h .,J. Z .,Hassabis,d .,Botvinick,M. (2018 年)。前额叶皮层作为一个元强化学习系统。bioRxiv。

[21] Botvinick,m .,Ritter,s .,Wang,j .,Kurth-Nelson,z .,Blundell,c .,和 Hassabis,D. (2019 年)。强化学习,有快有慢。认知科学趋势,23。

[22]里特尔,S. (2019)。情景回忆的元强化学习:奖励驱动学习的整合理论。博士论文。

[23] Pritzel,a .,Uria,b .,Srinivasan,s .,Badia,A. P .,Vinyals,o .,Hassabis,d .,Wierstra,d .,和 Blundell,C. (2017 年)。神经事件控制。更正,abs/1703.01988。

原载于 2020 年 1 月 20 日https://bkhmsi . github . io

圣地亚哥每小时能耗预测— I

原文:https://towardsdatascience.com/part-1-time-series-analysis-predicting-hourly-energy-consumption-of-san-diego-short-term-long-3a1dd1a589c9?source=collection_archive---------32-----------------------

我们将涵盖从不同来源导入和合并数据集、重采样、数据清理、EDA 和推理。

马克斯·本德在 Unsplash 上的照片

本文的第 1 部分将讨论能源(电力)消耗的基础知识,如何导入、重新采样和合并从不同来源(EDA)收集的数据集,并从圣地亚哥的能源消耗数据中得出一些基本推论。如果你只对建模部分感兴趣,那么请直接跳到这篇文章的第二部分。

[## 圣地亚哥每小时能源消耗预测(短期和长期预测)——II

时间序列基础&使用傅立叶级数处理多重季节性。使用(S)ARIMA(X)与线性预测…

towardsdatascience.com](/part-2-time-series-analysis-predicting-hourly-energy-consumption-of-san-diego-ii-f09665796c9)

在这些文章(第一部分和第二部分)中,我们将涵盖短期(一小时前和一周前)和长期(几个月前)预测。

nbviewer 上 Jupyter 笔记本的链接:
1。数据导入和 EDA (本帖涵盖)
2。构建 ML 模型和预测(在第 2 部分帖子中讨论)

整个项目的 Github 链接:小时 _ 能耗 _ 预测。

介绍

电力公司需要努力提前规划其发电厂中发电机组的分配,以匹配其区域能源需求,因为如果需求高于发电量,则可能导致几次停电,从而导致巨大的经济损失;另一方面,如果发电量高于需求,额外的电力将被浪费,并且还会在输电线路上产生不必要的负载。

因此,对于公用事业来说,预测能源消耗以便能够分配适当的资源来满足其需求是非常重要的。一年、一个月或一天的预测可以帮助电力公司规划更长的时间范围,但对于更平稳的日常操作,每小时(甚至更好)的预测可能非常有用。例如,如果电厂运营商得到下一个小时的高能源预测,他们可以通过打开更多的电厂来增加能源供应。

在这个项目中,我们将分析 SDGE 电力公司过去 5 年的每小时能耗数据,以发现一天中的小时、一周中的天、一年中的季节等的能耗趋势。,并检查外部温度和该地区的太阳能装置等因素是否会影响能源消耗。

电力公司可以利用开发的预测模型来有效地规划他们的发电操作,并平衡需求和适当的供应。

一些能源术语

  • 瞬时负载也称为需求,以瓦特(W、kW、MW、GW 等)为单位。).
  • 一段时间内消耗或产生的能量以瓦特小时(Wh、kWh、MWh、GWh 等)计量。)
  • 因为我们将使用的数据是 1 小时间隔数据,所以在该间隔期间的需求和能量将是相同的。因此,我们将在本文中交替使用能源和需求术语。如果你想潜得更深,请参考这个链接。
    注:峰值或最大负荷决定了一个电网所需的容量。例如,假设一个城市在 365x24 小时内的平均负荷是 10MW,但是在这 365x24 小时内的任何时刻观察到或可能观察到的最大峰值负荷是 20MW,那么该城市的发电厂基础设施(包括所有电源)的内置容量应该至少是 20MW。因此,平均而言,任何地区的发电装机容量都远大于该地区的平均预期需求。

术语说够了,让我们把剩下的“我们的能量”用于构建一些时间序列模型。

导入圣地亚哥地区的能耗数据

加州参与的公用事业地图(对于这个项目,我们将关注底部标记为圣地亚哥天然气和电力— SDGE 的红色区域)

导入数据:

该代码导入在 CAISO 地区运行的所有电力公司的每小时能耗数据,即 PGE、SCE、SDGE 和 VEA。它还包括 CAISO 总消耗量数据。

检查数据是否已正确导入。

同样,我们也可以检查 2014-2017 年的数据。

注意:在项目进行的时候,数据只提供到 2019 年 7 月,但如果你现在检查(2020 年 5 月),2019 年所有月份的数据都在网站上提供。这篇文章中显示的分析只考虑了 2014-2018 年的全年数据,但使用相同的代码可以很容易地添加 2019 年的剩余月份。

N 注:(2022 年 5 月更新)。我注意到 2019 年之前数据的存档链接不再活跃,我也无法在网站上找到更新的链接。但是自 2020 年以来,产生了更多的数据,并且链接中的“EMS 的历史每小时负荷数据”部分具有从 2019 年 1 月到 2022 年年中的数据,这对于该项目来说应该足够了。

从网站上读入数据并存储在字典中。然后组合字典中的所有关键字以生成单个数据帧。

原始数据框架,包括所有 CAISO 参与设施的每小时能耗值。

上述代码将为我们提供 4 家 CAISO 公用事业公司(即 PGE、SCE、SDGE 和 VEA)过去 5 年的每小时能耗值。它还会给出 CAISO 总数。稍后,我们将只提取这个项目的 SDGE 数据。

以下是在上述小时 1418 数据帧上执行的一些操作:

  • “日期”列已经是 datetime 格式,所以我们可以直接对该列使用 Datetime 操作。
  • 将能耗值转换成数字;在转换为 numeric 时,注意到列中的一些值是字符串,因此将 errors = ' compete '参数传递给 pd.to_numeric 方法。此外,在转换之后,检查该列是否有空值。
  • “日期”列数据中的某些值的格式为“201x-xx-xx yy:59:59.992”,因此使用 dt.floor 将其转换为“201 x-xx-xx YY:00:00”;这将使“日期”列中的日期时间行保持一致。

日期时间格式和转换为数值

  • 发现 dataframe 只有 3 个丢失的值,所以通过使用*errors = ' constrate '*我们没有丢失很多数据,这证明了这里使用' constrate '方法的合理性。我只是想警告一下,*错误= '强制'*并不是每次都可以使用的最好方法,你必须在使用它之前检查你的数据,否则它会导致很多空值。

处理缺失的能量值

圣地亚哥地区的原始能量时间序列如下所示。

以上 hourly1418 数据帧保存为' hourly1418CA.csv' 文件以备后用。我们将继续仅使用 SDGE 能耗值。

hSDGE1418 = pd.read_csv('hourly1418CA.csv',usecols=['Dates','SDGE'], parse_dates=['Dates'])

圣地亚哥能源消耗时间序列(y 轴代表每小时的能源消耗,单位为 MWh)。有关交互式 Plotly 图和查看 CAISO 内所有公用设施的能耗图,请参阅 EDA 和 ML 笔记本。

  • 43824 小时的数据(以兆瓦时为单位的能耗= 10⁶瓦时)
  • 平均值:2364.92,中位数:2298.0
  • 最小值:1437.08
  • 最大:4867.0

我们可以看到能源消耗在夏季有更高的峰值,并且有很强的多季节性模式。这意味着,能源消耗有每日、每周以及季节性的模式。我们稍后还将分析数据的趋势。

其他日期时间参数已添加到数据帧中,如下所示:

添加日期时间功能的代码

添加了日期时间功能的能耗数据框

非工作日:当天不是联邦假日就是周末
季节:11-5 月:冬季和 6-10 月:夏季(根据 SDGE
链接 )

导入天气数据

为了查看天气(特别是温度)对能耗的影响,我们将从 gov.noaa.ncdc 导入每小时的温度数据。圣地亚哥有两个或更多的气象站记录了天气数据。由于机场的天气数据通常更准确,不会受到附近建筑和工业的影响,因此我们将使用圣地亚哥国际机场的数据来进行这个项目。(从此链接,选择圣地亚哥县>圣地亚哥国际机场添加到购物车,即可下载所需数据)。

下载的天气数据有许多列,但我们将只关注'hourly dry bulb temperature'这是以华氏度为单位的室外温度。

天气数据每 7 分钟捕获一次,而能源消耗数据是每小时的数据,因此我必须在将天气数据与能源数据合并之前,通过计算每小时的平均温度,以每小时的间隔对天气数据进行重新采样。

hourly_weather = weatherdf_air.set_index('DATE').resample('H').mean()wehSDGE1418 = pd.merge(hSDGE1418, hourly_weather, how = 'outer', left_on = 'Dates', right_on= 'DATE')

太阳能/光伏安装数据

据观察,圣地亚哥的能源消耗在过去几年中总体上有所下降,并且在白天时间下降更为明显。因此,我们可以测试这一理论,也许圣地亚哥地区安装的太阳能容量在这些年里有所增加,因此当太阳出来时,越来越多的客户使用更少的能源,导致能源消耗的总体减少。我们可以通过导入 SDGE 地区的太阳能装置数据来检验这一理论。

太阳能装置数据从加州分布式
发电统计站点(直接数据链接)导入。该数据集包含许多参数,但我们将重点关注:
-批准日期:表示系统连接到电网开始运行的日期,以及
-系统大小 AC': ,表示安装在现场的太阳能电池板的总交流千瓦功率。

要获得有关数据的更多细节,您可以在我的报告中查看此工作簿。

光伏安装数据框 SDGEPV 。每天总共有多少千瓦的 PV 被激活。

  • 出于建模目的,我们对一天安装了多少光伏容量不感兴趣,而是想知道在任何特定的一天,该地区当前运行的光伏系统的总容量是多少。因此,使用累积的系统规模,我们希望看到该地区的总太阳能容量是如何整体增加的。
SDGEPVM['cum_AC_kW'] = SDGEPVM['AC_kW'].cumsum()##Truncating the PV installation data to the min and max dates' ##limits of the 'weather+energy' data - 'wehSDGE1418' and storing it ##as SDGEPVTSDGEPVT = SDGEPVM.loc[wehSDGE1418.Date.min():wehSDGE1418.Date.max(), ['AC_kW','cum_AC_kW']].reset_index()

基本上,这个想法是,如果客户有更多的光伏产品,他们将减少对电网供电的依赖(至少当太阳出来时),从而降低整体能源需求。因此,我们正在考虑在客户场所安装光伏(如住宅、商业建筑等)。).

让我们将 PV 数据集合并到之前合并的天气+能源数据帧中。

df = pd.merge(wehSDGE1418, SDGEPVT, left_on = 'Date', right_on = 'date_approved', how = 'left')*# dropping duplicate date columns*
df.drop(['DATE', 'date_approved'], axis=1, inplace=**True**)
  • 由于在 5 年内(2014-18 年)并不一定每天都安装太阳能电池板,因此 SDGEPVT 数据帧并不具有与能量数据帧 wehSDGE1418 匹配的所有行,这导致 AC_kWcum_AC_kW 列中的值缺失。
  • 我们可以在“ AC_kW ”栏中用 0 代替 NaN 来表示当天的 0 安装。
  • 并且由于累积安装的太阳能系统大小应该保持不变,直到遇到下一个非 NaN 值,使用向前填充方法来填充“ cum_AC_kW 列。
df['cum_AC_kW'] = df['cum_AC_kW'].fillna(method='ffill')
  • Forward fill 对除了前几行之外的所有行都有效,因为 SDGEPVT 的数据不是从 2014–01–01 00:00:00 开始作为我们的能源和天气数据,所以我们必须使用不同的方法来填充前几个缺失的值。所以,基本上初始缺失值应该等于第一个非 NaN(cum _ AC _ kW'减去'AC _ kW')。

在日光数据中填入 NaN 值

让我们探索一下阳光之城是如何用电的

绘制一些图表,从数据中获得洞察力。可以回答的一些问题是:

  • 检查整个时间段内任何特定一天的平均能耗变化。典型的日平均负荷曲线是一条在晚上达到峰值的曲线,因为大多数人晚上下班回家,打开灯、电视、空调等..
  • 绘制月平均负荷曲线。圣地亚哥夏天很热,但是冬天不冷,所以我们可以预计夏天的负荷会更高,因为商业和住宅建筑的冷负荷。
  • 查看每小时与工作日的能源消耗图,了解典型一周的总体消耗模式。
  • 温度对能耗有什么影响?
  • 用户电表后太阳能装置数量的增加是否导致了整个 SDGE 地区总能耗的下降?
  1. 绘制整个 2014 年至 2018 年期间的平均每小时负荷曲线

从平均每小时负载曲线图中,我们可以观察到负载如何在夜间保持较低,然后随着人们醒来而开始增加,然后在办公时间继续增加,并在晚上每个人回家并打开电器时达到峰值。

2.每小时与工作日的能耗对比,以了解某一周的能耗变化情况

可以看出,周一至周五的平均消费在夜间低于 2000 英镑,在白天有所增加,在晚上达到峰值(> 2800 英镑),然后再次下降到夜间。在周末也可以观察到同样的模式,但周末的总消费似乎比预期的工作日低,因为大多数商业建筑在周末不营业。

来自 SDGE 的网站:“如果客户可以将他们的一些能源使用转移到下午 4 点至晚上 9 点以外的低成本时段,他们就可以降低电费,并在更容易获得的时候,更好地利用更清洁的可再生能源,如风能和太阳能。”

3.可视化不同年份的能量值分布

从 2014 年到 2018 年,所有年份的分布都是双模态的,能耗的模态值每年都向左移动(朝向较低的能源负荷)。

这种峰值左移可以被认为是由客户站点(称为电表后)可再生能源装置的增加以及客户对需求响应计划的参与增加导致电网峰值需求降低引起的。

3.1.绘制相同的分布图,但仅在晚上 12 点

从上图中我们可以看到,从 2014 年到 2018 年,能源消耗分布已经明显向更低的能源消耗值转移,这种影响在早上 8 点到下午 5 点的白天时段更加明显(所有时段见 EDA 笔记本)。

  • 在白天时段发生这种转变的原因之一可能是在用户电表后面增加了更多的可再生能源,如太阳能。我们将在后面看到,在过去的 5 年里,SDGE 的太阳能装置有了相当大的增长。导致这种下降的因素有很多,包括参与能源效率和需求响应计划的人数增加等。但是我们将只关注这个项目的太阳能装置。

4.一起探索能源和天气数据

多年来能源消耗(红色)随干球温度(蓝色)的变化

温度与能耗

  • 正如之前所怀疑的,我们可以看到能耗和温度确实是相互影响的,而且它们之间似乎有某种程度的相关性。
  • 更重要的是,我们可以看到最高能耗值出现在最高温度下。这可能是因为温度较高时空调负荷较高,在夏季需要更多空调负荷。在圣地亚哥,冬天并不寒冷,但是夏天会非常热,所以人们在冬天不怎么使用加热器,因为他们在夏天会使用空调。
**for** season **in** SDGE_t_pv['season'].unique():corrcoef, pvalue = scipy.stats.pearsonr(SDGE_t_pv[SDGE_t_pv['season'] == season]['SDGE'], \SDGE_t_pv[SDGE_t_pv['season'] == season]['HourlyDryBulbTemperature'])print('pearson correlation coefficient and pvalue for '+season, corrcoef, pvalue)

冬季皮尔逊相关系数和 p 值:0.32
夏季皮尔逊相关系数和 p 值:0.65

如上文第 3.1 节所述,从 2014 年到 2018 年,白天的能源消耗似乎有所下降。现在,这可能是由于更严格的能源效率措施被强制执行,或者对不同类别的纳税人(住宅、商业、农业等)的激励增加。)安装太阳能、风能等自发电资源。和/或能量存储,以避免更高的能量需求。据观察,多年来能源消耗的减少在白天更为明显,因此我们可以测试这一理论,即安装在公用事业区域的太阳能容量可能在多年来有所增加,正如我们将在下面看到的那样。

2014 年至 2018 年圣地亚哥累计太阳能装机容量(客户位置)

历年白天最大能耗与历年光伏装机累计装机容量之间的相关系数。还绘制了光伏安装与 6 个月滚动最大能耗的关系

**>> Energy consumption vs PV installed capacity: pearson correlation coefficient and pvalue for winter -0.515, 0.0
>> Energy consumption vs PV installed capacity: pearson correlation coefficient and pvalue for summer -0.338, 0.0**

光伏安装(蓝色)与 6 个月滚动最大能耗(红色)。请注意,轴值不是从零(0)开始。

  • 这种相关性似乎对两个季节都很重要,对冬季月份更强。这有点违反直觉,但较冷的温度实际上比温暖的温度更有利于太阳能电池板。这种关系适用于大多数类型的太阳能电池板——与安装过程本身无关。在世界各地的实验室进行的研究清楚地表明,温度的升高对测试的太阳能电池板的总太阳能输出有相反的影响。换句话说,温度越高,太阳能光伏系统的效率就越低。
  • 因此,在所有条件相同的情况下,你在六月、七月、八月的月水电费节省会比十二月、二月和一月少。ref:https://www . sunline energy . com/solar-PV-power-output-San-diegos-winter-months/

还有,“圣地亚哥,美国另一个日照最好的城市,冬天比夏天拥有更多的阳光”。(参考链接)

结论

我们已经看到了温度和光伏装机容量对圣地亚哥市能源需求的影响。由于气温较高,夏季的能源需求明显高于冬季。安装的太阳能电池板容量似乎也对这些年的能源消耗有轻微的(减少的)影响。而且,能源消耗有多种季节模式。

在这篇文章的第二部分,我们将从使用传统的预测算法如 SARIMAX 和线性回归建立简单的短期预测模型开始。然后,我们还将尝试使用非线性方法进行长期预测,如随机森林、XGBoost 以及集合模型(XGBoost + FB Prophet)。

感谢阅读。第 2 部分见。

免责声明:我在所有公用事业中选择了圣地亚哥,因为,I .它服务的区域比其他公用事业小,所以我们可以使用来自单一来源的温度数据,而不会有太大的变化(实际上圣地亚哥的天气模式变化很大,但对于本项目,我们将忽略这一点); ii .我是加州大学圣迭戈分校的校友。

第 2 部分:用 Python 和 Google Cloud 函数构建一个简单的 ETL 管道——MySQL 到 BigQuery(通过 SSH)

原文:https://towardsdatascience.com/part-2-building-a-simple-etl-pipeline-with-python-and-google-cloud-functions-mysql-to-bigquery-4e1987f9f89b?source=collection_archive---------20-----------------------

使用 Google Cloud 函数从 MySQL 数据库中提取数据并加载到 Google BigQuery 中

在第 1 部分中,我们看了如何从 FTP 服务器提取 csv 文件,以及如何使用云函数将其加载到 Google BigQuery 中。在本文中,我们将做同样的事情,但这一次,我们将从 MySQL 数据库中提取数据。

有很多 ETL 工具,有时它们可能会让人不知所措,特别是当你只想将文件从 A 点复制到 b 点时。所以今天,我将向你展示如何使用 python 3.6 和谷歌云功能从 MySQL 数据库中提取数据(extract)、修改数据(Transform)并将其加载到谷歌 BigQuery 表(load)中。

在本文中,我们将做以下工作:

  • 设置云功能
  • 提取数据
  • 转换数据
  • 加载数据
  • 自动化我们的管道

首先,什么是 ETL?

提取、转换、加载(ETL)是将数据从一个或多个源复制到目标系统的一般过程,目标系统以不同于源的方式或在不同于源的上下文中表示数据。—维基百科

这是我们的 ETL 管道最终的样子:

ETL 管道(使用 Lucidchart 创建)

Google Cloud Functions:Cloud Functions(CF)是 Google Cloud 的无服务器平台,用于执行响应特定事件的脚本,如 HTTP 请求或数据库更新。CF 的替代方案是 AWS Lambda 或 Azure Functions 。

设置您的云功能

  • 进入云功能概述页面。
    确保您启用了云功能的项目被选中。
  • 单击创建函数。
  • 说出你的函数。
  • 在触发器字段中,选择 HTTP 触发器。
  • 在源代码字段中,选择内联编辑器。在本练习中,我们将编写一些自定义代码,因此您可以在编辑器中删除默认代码。
  • 使用运行时下拉列表选择运行时。
  • 认证:在本例中,我们将“允许未经认证的调用”,但建议使用服务帐户来访问云函数,并在我们将使用的云调度器服务帐户上授予云函数的“权限调用程序”。更多详情在文末。

确保您的运行时设置为“Python 3.7”,并在“高级选项”下将区域更改为离您最近的区域。在撰写本文时,CF 并不是在每个谷歌数据中心区域都可用,所以请点击这里的查看哪里启用了云功能。

完成这些步骤后,您的显示应该如下所示:

截图来自 GCP 控制台

我们的自定义代码

一个云函数有两个文件;一个 main.py 和一个 requirements.txt 文件。后者托管我们脚本工作所需的所有文件依赖项,因此单击 requirements.txt 选项卡,并确保编辑器中包含这些依赖项,如下所示:

提取

现在在 main.py 选项卡中,您可以开始包含下面的代码。我们创建了一个名为“ handler 的函数,以后用 HTTP 请求访问云函数时会用到这个函数。然后,我们使用必要的凭证登录到 MySQL 服务器,在第 30 行,编写从数据库中提取数据所需的 SQL 查询。

获得正确的 ssh 隧道细节很重要,这样就不会遇到认证问题。SSHTunnel 是一个很好的 Python 库。

注意:为了保护你的秘密管理者证书,请遵循这个指南。

改变

因为我们现在有一个名为“*df”*的熊猫数据框架,我们可以像这样操作熊猫数据:

df . group by([' Name '])[[' Orders ']]。agg('sum')

这将对“orders”列中的所有订单进行汇总,并根据数据帧的“name”列中的每个唯一名称进行分组。在这个特殊的例子中,我没有包含任何转换,但是如果需要的话,您可以在第 30 行之后这样做。

负荷

现在,确保您创建了您的 BigQuery 表。然后我们简单地使用下面的代码将转换后的 CSV 文件加载到您创建的 BigQuery 表中。

  • auto detect = True:-由于我们启用了“自动检测”,所以在将数据加载到表中时,我们不需要提供模式,因为它将基于 Dataframe 中的数据进行推断。
  • WRITE _ disposition = " WRITE _ TRUNCATE ":-该作业将截断表数据并从头开始写入。
  • source _ format=big query。source format . NEWLINE _ DELIMITED _ JSON
  • load _ table _ from _ data frame*:-*一个不错的 BigQuery 函数,可以将数据从一个**pandas.DataFrame**加载到一个[**Table**](https://googleapis.dev/python/bigquery/latest/generated/google.cloud.bigquery.table.Table.html#google.cloud.bigquery.table.Table)

当您完成编写脚本时,您可以通过单击“创建”来部署云功能。当该功能成功部署后,您应该会看到一个绿色的复选标记。

来源

使自动化

现在剩下要做的就是创建一个 cron 作业(Cloud Scheduler ),它将在某个预定义的时间间隔自动调用 CF。好消息是,在谷歌云平台上创建 cron jobs 非常简单,也是最简单的部分。你可以在这里按照的指示或者复制下图。

来源

截图自 GCP

这里的“频率”字段将在每天凌晨 1:59 运行我们的脚本。

你可以使用这个很酷的 站点编辑器 进行简单的 cron 调度表达式。

既然我们的数据已经存放在数据仓库中,我们可以将它连接到任何可视化工具并对其进行分析。

后续步骤

如果您不想允许未经身份验证的调用,请为 Cloud Scheduler 设置 HTTP 目标身份验证。如果您设置了具有适当凭据的关联服务帐户,云调度程序可以调用需要身份验证的 HTTP 目标。点击阅读更多。

就是这样。希望这对你有帮助。这是一种非常简单的开发 ETL 的方法,任何人都可以在其上进行构建。

你可以 成为中等会员 享受更多这样的故事。

你可以在 Github 上找到完整脚本的链接。

第 2 部分—使用 Python 和 Heroku 创建实时交互式仪表盘

原文:https://towardsdatascience.com/part-2-create-live-interactive-dashboards-with-python-and-heroku-b74701a75746?source=collection_archive---------55-----------------------

在 Heroku 云平台上部署您的 Streamlit 应用程序的简单说明

斯蒂芬·道森在 Unsplash 上拍摄的照片

介绍

如果你想在云平台上部署一个交互式仪表盘或你的投资组合作为一个网页,Heroku 是一个部署你的仪表盘的好应用。在我们之前的帖子中,我们讨论了如何使用 Streamlit 在 Python 中构建交互式仪表盘。在这里,我们将在云平台中部署我们的 streamlit 应用程序。

赫罗库

Heroku 是一个云平台,在虚拟容器(Dynos)中运行我们的应用程序,这些应用程序在运行时环境中执行。这些容器支持许多不同的语言,如 Ruby、Scala、Python、Java 等。它还提供定制的构建包,我们可以用它来部署任何其他语言的应用程序。

设置 Heroku

  • 在 Heroku 中创建一个帐户,然后在那里创建一个新应用程序。

  • 我们可以用不同的方式部署我们的应用程序,但在这篇文章中,我们将看到如何通过 Github 部署我们的代码。我们可以把 Github 账户和 Heroku 联系起来。

Heroku 的设置文件

现在我们已经准备好将 Github 代码部署到 Heroku 了。现在我们需要在代码中添加额外的文件来帮助我们自动运行代码。为此,我们需要在 Github 文件夹中添加两个额外的文件。

  • 概要文件 —我们需要创建一个名为 Procfile 的文本文件,没有任何扩展名。它是一个声明如何运行以及运行什么命令的文件。

格式:

web: sh setup.sh && streamlit run <filename>.py

示例:

web: sh setup.sh && streamlit run covid_data.py
  • setup.sh —我们还需要创建一个名为 setup.sh 的文件,我们将在其中写入配置,并为 streamlit 创建一个文件夹。我们只需要将下面的命令粘贴到文件中。
mkdir -p ~/.streamlit/
echo "\[server]\n\ 
headless = true\n\ 
port = $PORT\n\ 
enableCORS = false\n\ 
\n\ 
" > ~/.streamlit/config.toml

如果我们的文件夹中没有 requirement.txt 文件。我们可以使用 pipreqs 包来创建它。

$ cd ~/<folder_path>\ 
$ pipreqs
$ git add requirements.txt 
$ git commit -m "requirements.txt" 
$ git push

通过 Github 部署 Heroku

现在我们开始部署我们的项目。连接我们要部署的 Github 库,然后部署 branch。如果我们想要自动部署我们所做的每一个变更/提交,我们需要点击按钮"Enable Automatic deployments"

如何经营 Heroku

现在我们的 Streamlit 应用程序已经部署好了,我们需要运行 Heroku。

$ heroku ps:scale web=1 -a <app_name> $ heroku open -a<app_name>

最后,我们可以在云平台中看到我们的 Streamlit 应用程序

注意:在阅读下面这篇文章时,该 URL 可能没有激活。

所有的代码

这里是 Github repo 的所有代码,包括我们在这个博客中使用的所有代码。

这个帖子到此为止。希望对你有帮助。敬请关注新的有趣博客。

原载于 2020 年 7 月 2 日【https://confusedcoders.com】

探索寻路图算法

原文:https://towardsdatascience.com/part-2-exploring-pathfinding-graph-algorithms-e194ffb7f569?source=collection_archive---------21-----------------------

旅游的游客

深入探究 Neo4j 图形数据科学库中可用的寻路算法

在系列的第一部分,我们从 WikiData API 构建了一个位于西班牙的古迹的知识图。现在我们将戴上图形数据科学护目镜,探索 Neo4j 图形数据科学库中可用的各种寻路算法。更重要的是,我们来看看圣诞老人问题的强力解决方案。现在,你可能想知道圣诞老人问题是什么。这是旅行推销员问题的一个变种,除了我们不要求解决方案在开始的同一个城市结束。这是因为圣诞老人有弯曲时空连续体的能力,一旦他送完东西,就会立刻飞回北极。

议程

  1. 推断古迹的空间网络
  2. 用 cypher projection 加载内存中的投影图
  3. 弱连通分量算法
  4. 最短路径算法
  5. Yen 的 k-最短路径算法
  6. 单源最短路径算法
  7. 最小生成树算法
  8. 随机行走算法
  9. 旅行推销员问题
  10. 结论

推断古迹的空间网络

目前,我们在图表中的纪念碑之间没有直接的关系。然而,我们有他们的 GPS 定位,这使我们能够识别附近的纪念碑。这样,我们可以推断出一个纪念碑的空间网络。

过程非常类似于推断相似性网络。我们通常不希望得到一个完整的图,其中每个节点都与所有其他节点相连。这将违背演示寻路算法的目的,因为任何两个节点之间的最短路径将总是直线,这将被表示为两个节点之间的直接关系。在我们的例子中,我们将把每个纪念碑连接到距离不到 100 公里的五个最近的纪念碑。这两个数字完全是任意的。您可以根据自己的情况选择其他选项。

MATCH (m1:Monument),(m2:Monument) 
WHERE id(m1) > id(m2) 
WITH m1,m2, distance(m1.location_point,m2.location_point) as distance 
ORDER BY distance ASC
WHERE distance < 100000
WITH m1,collect({node:m2,distance:distance})[..5] as nearest 
UNWIND nearest as near 
WITH m1, near, near.node as nearest_node 
MERGE (m1)-[m:NEAR]-(nearest_node) SET m.distance = near.distance

用 cypher projection 加载内存中的投影图

让我们快速回顾一下 GDS 图书馆是如何工作的。

图片借用自官方文档。

图表分析管道由三部分组成。在第一部分中,图形加载器从 Neo4j 中读取存储的图形,并将其作为内存中的投影图形加载。我们可以使用本地投影或 cypher 投影来加载投影图。第二步,我们按顺序执行图算法。我们可以使用一个图算法的结果作为另一个图算法的输入。最后但同样重要的是,我们将结果存储或流回 Neo4j。

这里,我们将使用 cypher 投影来加载内存中的图形。我建议你看一下官方文档了解更多关于它如何工作的细节。在 node 语句中,我们将描述图中的所有纪念碑,并添加它们的架构风格作为节点标签。添加一个定制的节点标签将允许我们在算法执行时按照架构风格过滤节点。在关系声明中,我们将描述纪念碑之间的所有链接,并包括距离属性,我们将使用该属性作为关系权重。

CALL gds.graph.create.cypher('monuments','MATCH (m:Monument)-[:ARCHITECTURE]->(a) RETURN id(m) as id, collect(a.name) as labels','MATCH (m1:Monument)-[r:NEAR]-(m2:Monument) RETURN id(m1) as source, id(m2) as target, r.distance as distance')

弱连通分量算法

尽管弱连通分量算法不是寻路算法,但它是几乎所有图形分析的一部分。它用于在我们的图中查找不连接的组件或岛。我们将从运行算法的stats模式开始。

CALL gds.wcc.stats('monuments') 
YIELD componentCount, componentDistribution

结果

弱连通分量统计结果

我们的古迹网络有六个独立的组成部分。这些结果是真实世界数据集的典型结果。我们有一个包含 98%的节点和几个漂浮在周围的小岛的超级组件。让我们检查较小的组件。

CALL gds.wcc.stream('monuments')
YIELD nodeId, componentId 
WITH componentId, gds.util.asNode(nodeId) as node
OPTIONAL MATCH (node)-[:IS_IN*2..2]->(state)
RETURN componentId, count(*) as component_size,collect(node.name) as monuments, collect(distinct state.id) as state
ORDER BY component_size DESC 
SKIP 1

结果

较小的弱连通分量成员

五个较小的部分中有三个位于加那利群岛,一个位于巴利阿里群岛,特别是在马略卡岛。通过由 Estelle Scifo 开发的 Neomap 应用程序,我们可以在地图上看到加那利群岛的组成部分。

其中一个部分横跨 Fuerteventura 和 Lanzarote 的两个纪念碑。第二个由位于特内里费岛和大加那利岛的几个纪念碑组成。在左边,埃尔耶罗岛上有一座单独的纪念碑。它们是独立的组件,因为它们之间没有联系。组件之间没有连接意味着距离超过 100 公里,因为这是我们推断空间网络时选择的阈值。

又及:如果你喜欢水上活动,我强烈推荐你去加那利群岛。

最短路径算法

我们将使用的第一个寻路图算法是最短路径算法。它查找两个节点之间的最短加权路径。我们定义开始节点和结束节点,并指定在计算最短路径时算法应该考虑哪个关系权重属性。

MATCH (s:Monument{name:'Iglesia de Santo Domingo'}),  (e:Monument{name:'Colegiata de Santa María de Piasca'})
CALL gds.alpha.shortestPath.stream('monuments',{startNode:s,endNode:e,relationshipWeightProperty:'distance'})
YIELD nodeId, cost
RETURN gds.util.asNode(nodeId).name as monument, cost

结果

成本以米为单位的距离来表示。我们可以用 Neomap 稍加修改的版本来可视化最短路径。我已经定制了纪念碑的弹出窗口,包括它的图像和建筑风格。

你可能会注意到,我们忽略了圣克鲁斯·德·坎加斯·德·昂尼斯纪念碑,它位于图片的中间偏右。从 Iglesia de San Emeterio 到 Santo Toribio de Liébana,稍微绕一点路就会比直线行驶的路程长。

如果我们想为一堂建筑课计划一次旅行,并且沿途只参观受哥特式或罗马式建筑影响的纪念碑,会怎么样?利用 GDS 图书馆,计划这样的旅行是非常容易的,因为我们可以用参数nodeLabels过滤算法可以访问的节点。

MATCH (s:Monument{name:'Iglesia de Santo Domingo'}),  (t:Monument{name:'Colegiata de Santa María de Piasca'})
CALL gds.alpha.shortestPath.stream('monuments',{startNode:s,endNode:t,relationshipWeightProperty:'distance',nodeLabels:['Gothic architecture','Romanesque architecture']}) 
YIELD nodeId, cost
RETURN gds.util.asNode(nodeId).name as monument, cost

结果

这次的路线有点不同,因为算法只能访问受哥特式或罗马式建筑风格影响的纪念碑。

Yen 的 k-最短路径算法

我们已经学习了如何计算一对节点之间的最短加权路径。如果我们是更谨慎的游客,想要找到前三条最短路径,会怎么样?有一个后备计划,以防途中可能会发生意想不到的事情,这总是一个好主意。在这个场景中,我们可以使用 Yen 的 k-shortest path 算法。语法几乎与最短路径算法相同,除了添加的k参数,该参数定义了我们希望找到多少条最短路径。

MATCH (s:Monument{name:'Iglesia de Santo Domingo'}),(t:Monument{name:'Colegiata de Santa María de Piasca'})
CALL gds.alpha.kShortestPaths.stream('monuments',{startNode:s,endNode:t,k:3,relationshipWeightProperty:'distance'}) 
YIELD index,nodeIds,costs
RETURN index,[nodeId in nodeIds | gds.util.asNode(nodeId).name] as monuments,apoc.coll.sum(costs) as total_cost

结果

Yen 的 k-最短路径算法结果

这三条路几乎一样长,只差几百米。仔细看,三个变体中只有第二站不一样。如此小的差异可归因于我们的空间网络和示例节点对的性质。

单源最短路径算法

使用单源最短路径算法,我们定义起始节点,并搜索到网络中所有其他节点的最短加权路径。我们将检查一个加那利组件,以将最短路径的数量限制到一个合理的数量。

我们将检查特内里费岛—大加那利岛部分,并选择拉古纳大教堂作为起点。该算法试图找到到网络中所有其他节点的最短路径,如果不存在这样的路径,它将返回无穷大值作为结果。我们将使用gds.util.isFinite过程过滤掉不可到达的节点。

MATCH (start:Monument{name:’Cathedral of La Laguna’})
CALL gds.alpha.shortestPaths.stream(‘monuments’,{startNode:start, relationshipWeightProperty:’distance’})
YIELD nodeId, distance
WHERE gds.util.isFinite(distance) = True
RETURN gds.util.asNode(nodeId).name as monument,distance
ORDER BY distance ASC

结果

离拉古纳大教堂最近的纪念碑是康塞普西翁大教堂,只有 420 米远。在特内里费岛上似乎有两座康塞普西翁大教堂,我们可以观察到它在我们的搜索结果中出现了两次。在我们的网络中,距离拉古纳大教堂最远的纪念碑是圣胡安包蒂斯塔大教堂。

如果我们想找到从拉古纳大教堂到所有可到达的新古典主义纪念碑的最短路径的成本,我们可以通过nodeLabels参数轻松实现。

MATCH (start:Monument{name:'Cathedral of La Laguna'})
CALL gds.alpha.shortestPaths.stream('monuments',{startNode:start, relationshipWeightProperty:'distance',    nodeLabels:['Neoclassical architecture']})
YIELD nodeId, distance
WHERE gds.util.isFinite(distance) = True
RETURN gds.util.asNode(nodeId).name as monument,distance
ORDER BY distance ASC

结果

在特内里费岛和大加那利群岛上似乎只有四座新古典主义纪念碑。

最小重量生成树算法

最小权重生成树算法从一个给定的节点开始,计算连接所有可达节点的生成树,其关系权重之和最小。例如,如果我们想用光缆或电缆连接特内里费岛和大加那利岛的所有古迹,我们将使用最小重量生成树算法。

MATCH (start:Monument{name:’Cathedral of La Laguna’})
CALL gds.alpha.spanningTree.minimum.write(‘monuments’,{startNodeId:id(start),relationshipWeightProperty:’distance’,weightWriteProperty:’cost’})
YIELD effectiveNodeCount
RETURN effectiveNodeCount

结果

最小重量生成树算法结果在 Neo4j 浏览器中可视化

目前只有算法的write模式可用。我们可以用 Neomap 可视化我们潜在的电缆路径。

随机行走算法

我们可以想象随机漫步算法试图模仿喝醉的人群穿越网络。他们可能向左,或向右,向前两步,向后一步,我们永远不知道。要看人群醉到什么程度了。我们可以使用这种算法来提供随机的旅行建议。想象一下,我们刚刚参观了巴塞罗那大学历史建筑,但不确定接下来应该看哪些古迹。

MATCH (m:Monument{name:"University of Barcelona historical building"})
CALL gds.alpha.randomWalk.stream('monuments',{start:id(m), walks:3, steps:5})
YIELD nodeIds
RETURN [nodeId in nodeIds | gds.util.asNode(nodeId).name] as result

结果

随机行走算法结果

记住,我们提到过随机行走算法试图模仿一个喝醉的人穿越网络。一个喝醉的人可能会两次参观同一个纪念碑而不在乎。例如,在第一个和第三个建议中,一个纪念碑出现了两次。幸运的是,我们有一些选项可以用以下两个参数来影响算法在 node2vec 模式下如何遍历网络:

return:该参数控制遍历中立即重新访问节点的可能性。将它设置为较高的值(> max(inOut,1))可以确保我们不太可能在接下来的两步中对已经访问过的节点进行采样。

inOut:该参数允许搜索区分“向内”和“向外”节点。如果 inOut > 1,则随机游走偏向靠近节点 t 的节点,相比之下,如果 inOut < 1, the walk is more inclined to visit nodes that are further away from the node t.

则两个参数的定义是从 原 Node2vec 论文 中总结出来的。

我们想推荐离我们的起点很近的纪念碑,所以我们选择参数inOut大于 1。我们当然希望避免在遍历过程中重新访问已经访问过的节点,所以我们选择return参数大于inOut参数。

MATCH (m:Monument{name:"University of Barcelona historical building"})
CALL gds.alpha.randomWalk.stream('monuments',{start:id(m), walks:3, steps:5, mode:'node2vec', inOut:5, return:10})
YIELD nodeIds
RETURN [nodeId in nodeIds | gds.util.asNode(nodeId).name] as result

结果

node2vec 模式下的随机游走算法

不幸的是,return参数确保我们不太可能在接下来的两步中对已经访问过的节点进行采样。这意味着我们不能确定重复的东西不会在我们散步的时候出现。在我们的例子中,Casa Batlló在第一个建议中出现了两次。我们可以通过创建更长的步行建议并在向用户显示结果之前过滤掉重复的建议来解决这个问题。在下面的查询中,我们计算九步长的步行,过滤掉重复的,只返回前五个结果。

MATCH (m:Monument{name:"University of Barcelona historical building"})
CALL gds.alpha.randomWalk.stream('monuments',{start:id(m), walks:3, steps:9, mode:'node2vec', inOut:5, return:10})
YIELD nodeIds
RETURN apoc.coll.toSet([nodeId in nodeIds | gds.util.asNode(nodeId).name])[..5] as result

结果

移除重复项后的随机游走算法结果

通过这种方式,我们可以确保结果不包含重复项。现在,我们可以用我们的旅行推荐应用程序来可视化结果。

旅行推销员问题

最重要的是,我们将解决旅行推销员问题的圣诞老人变体。如前所述,唯一的区别是我们省略了在起始位置结束的要求。我在大卫·巴顿写的游戏圣诞市场帖子中找到了这个问题的灵感。我把所有的荣誉都归功于大卫·巴顿,是他想出了这个解决方案。我的贡献是更新它,以便与 Neo4j 4.0 和 GDS 图书馆一起工作。

比方说我们想找到这座纪念碑之间的最佳路线:

:param selection => ["Castell de Santa Pau","Castell de Sant Jaume","Castell de Vilaüt","Castell de Sarraí","Castell de Solius","Portal d'Albanyà","Castell de Sant Gregori","Casa Frigola"]

我们把解决方案分成两步。首先,我们使用gds.alpha.shortestPath算法计算所有选定纪念碑对之间的最短路径,并将结果存储为给定节点对之间的 SHORTEST_ROUTE_TO 关系。我们将总成本和沿最短路径的所有中间节点保存为 SHORTEST_ROUTE_TO 关系的属性。

WITH $selection as selection
MATCH (c:Monument)
WHERE c.name in selection
WITH collect(c) as monuments
UNWIND monuments as c1
WITH c1,[c in monuments where c.name > c1.name | c] as c2s,monuments
UNWIND c2s as c2
CALL gds.alpha.shortestPath.stream('monuments',{startNode:c1,endNode:c2,relationshipWeightProperty:'distance'})
YIELD nodeId, cost
WITH c1,c2,max(cost) as totalCost,collect(nodeId) as shortestHopNodeIds
MERGE (c1) -[r:SHORTEST_ROUTE_TO]- (c2)
SET r.cost = totalCost,r.shortestHopNodeIds = shortestHopNodeIds

完成第一步后,我们创建了所选纪念碑之间的 SHORTEST_ROUTE_TO 关系的完整图表。

旅行推销员问题第一步

在第二步中,我们将使用apoc.path.expandConfig过程。它使我们能够执行可变长度的路径遍历,并对遍历进行细粒度控制。查看文档了解更多详情。

我们允许程序仅遍历带有relationshipFilter参数的 SHORTEST_ROUTE_TO 关系,并仅访问带有whitelistNodes参数的选定纪念碑。我们通过定义遍历的跳数或级别数(minLevelmaxLevel)并使用uniqueness参数来确保所有选择的节点必须被恰好访问一次。我知道这很难理解,如果你需要帮助,我建议你在 Neo4j 社区网站上提问。然后,我们选择具有最小关系权重和的路径作为解决方案。因为我们计算了所选古迹之间所有可能的路线,所以这是旅行商问题的一种蛮力解法。

WITH $selection as selection
MATCH (c:Monument) 
WHERE c.name in selection
WITH collect(c) as monuments
UNWIND monuments as c1
WITH c1,[c in monuments where c.name > c1.name | c] as c2s,monuments,(size(monuments) - 1) as level
UNWIND c2s as c2
CALL apoc.path.expandConfig(c1, {relationshipFilter: 'SHORTEST_ROUTE_TO',minLevel: level,maxLevel: level,whitelistNodes: monuments,terminatorNodes: [c2],uniqueness: 'NODE_PATH'}) 
YIELD path
WITH path,reduce(cost = 0, x in relationships(path) | cost + x.cost) as totalCost
ORDER BY totalCost LIMIT 1
WITH path,totalCost,apoc.coll.flatten([r in relationships(path) | r.shortestHopNodeIds]) as intermediate_stops,[n in nodes(path) | id(n)] as node_ids
RETURN  [n in nodes(path) | n.name] as path,round(totalCost) as total_distance,[optional in intermediate_stops where not optional in node_ids | gds.util.asNode(optional).name] as optional_stops

结果

圣诞老人解决方案

在结果的“路径”列中,我们有一个有序排列的要参观的选定古迹。我们的旅行将从卡斯特尔德圣豪梅开始,继续到卡斯特尔德维拉乌特等等。我们可以称之为西班牙城堡参观之旅,因为我们选择了六个城堡,我们可以选择沿途参观四个。该路径的总空中距离为 126 公里。让我们用旅行推荐应用程序来可视化结果。

红色标记是选定的纪念碑,蓝色标记是沿途可选的停靠点。

结论

我们已经用一些真实世界的用例展示了 Neo4j 图形数据科学库中可用的大多数寻路算法。这个系列剩下的唯一难题是完成旅行推荐应用程序。我计划在本系列的第三部分展示这个应用程序。在那之前,我鼓励你尝试各种 GDS 库算法,或者尝试在一个 Neo4j 沙盒实例上重现这个系列。如果您有任何进一步的问题,在 Neo4j 社区网站上有一群 Neo4j 专家随时可以帮助您。

和往常一样,代码可以在 GitHub 上获得。

圣地亚哥每小时能耗预测—ⅱ

原文:https://towardsdatascience.com/part-2-time-series-analysis-predicting-hourly-energy-consumption-of-san-diego-ii-f09665796c9?source=collection_archive---------8-----------------------

时间序列基础&使用傅立叶级数处理多重季节性。使用 ARIMA(X)与线性回归、随机森林、XGBoost 和 FBProphet+XGB 进行预测。

卢卡斯·戴维斯在 Unsplash 上的照片

这篇文章的第 1 部分讲述了能源(电力)消耗的基础知识,如何导入、重采样和合并从不同来源和 EDA 收集的数据集。从 San Deigo 的能源消耗数据以及温度和太阳能电池板安装数据中也提取了一些推论。

[## 预测圣地亚哥的每小时能源消耗(短期和长期预测)— I

在第 1 部分中,我们将介绍从不同来源导入和合并数据集、重采样、数据清理、EDA 和…

towardsdatascience.com](/part-1-time-series-analysis-predicting-hourly-energy-consumption-of-san-diego-short-term-long-3a1dd1a589c9)

在这篇文章中,我将探讨一些时间序列模型,如持续预测(作为基线),ARIMA 和 FB 先知;然后扩展我的方法,包括线性回归、随机森林、XGBoost 和一个集合模型,看看这些线性和非线性方法是否能准确地模拟我们的时间序列。

nbviewer 上 Jupyter 笔记本的链接:
1。数据导入和 EDA (包含在第 1 部分中)
2。构建 ML 模型和预测(在本文中讨论)

如果你想要一个非常详细的时间序列数据处理的解释,建模和有效地可视化时间序列数据,那么请参阅上面列出的第二个笔记本。说了这么多,我还是会尽量涵盖本帖的重要话题。

整个项目的 Github 链接:小时 _ 能耗 _ 预测。

能耗数据

以下是上一篇文章中的数据和一些新增功能:

#Import the 5 years of hourly energy consumption data previously #cleaned, explored, and stored as 'hourly1418_energy_temp_PV.csv' in # Part 1sdge = pd.read_csv('hourly1418_energy_temp_PV.csv', index_col = 'Dates', parse_dates=['Dates', 'Date'])

用于预测的数据

  • SDGE:我们的目标变量,圣地亚哥的每小时能耗(MWh )(也是每小时负荷或需求)
  • 非工作日:如果当天是周末或假日,则为 0(二进制)
  • 每小时干球温度:在圣地亚哥机场测量的干球温度,单位为华氏度
  • cum_AC_kW:客户现场太阳能电池板的累计安装容量(直到索引栏中给出的日期),单位为 kW

圣地亚哥能源消耗时间序列(y 轴代表每小时的能源消耗,单位为兆瓦时)。有关交互式 Plotly 图和查看 CAISO 内所有公用设施的能耗图,请参见上面列出的 EDA 和 ML 笔记本。

从前面第 1 部分的分析中观察到的一些情况:

  • 43824 小时(行)的数据(2014-2018 年 5 年)
  • SDGE:最小值:1437.08,平均值:2364.92,中间值:2298.0,最大值:4867.0
  • 时间序列有多种季节模式——每天、每周和每年。
  • 略有下降趋势,与太阳能装机容量成反比
  • 能耗与温度高度相关。

我使用了从 2014 年 1 月 1 日到 2018 年 3 月 31 日的时间序列作为我的训练数据。并预测了 2018 年 4 月 1 日至 12 月 31 日的每小时能耗值(整个数据的约 15%)。

最终目标

该项目的最终目标是:“电力公司可以利用开发的预测模型来有效地规划其发电运营,并通过适当的供应平衡需求。有效的预测对于电力公司规划其日常运营、满足其客户的能源需求以及避免任何过量发电非常有用。"

基本上,我们希望将 ML 模型拟合到我们的每小时能源消耗时间序列中,并使用它来预测圣地亚哥未来的能源消耗。

预测窗口 在任何时间序列问题中,预先定义预测的窗口是非常重要的。在这里,我测试了未来 1 小时、1 周和 8 个月的模型。

使用的误差指标 我已经为训练集和测试集的每个模型计算了 R2 得分、MAE、RMSE 和 MAPE 。在这 4 个指标中,MAPE将被选中,选出最佳型号。MAPE 帮助我们理解绝对值的%误差,并且对时间序列的绝对量级漠不关心。

假设

  • 未来的太阳能电池板安装和温度数据对我们来说很容易获得,我们不需要为它们运行单独的预测(我希望!).在现实世界中,我们需要使用这些独立变量的预测值(或者至少使用温度的平均期望值和基于过去数据的估计未来太阳能安装量)。但是为了简单起见,我在这个项目中使用了这些变量的实际观察值。

事不宜迟,让我们把精力集中在时间序列预测问题上。

那么,时间序列有什么特别之处呢

时间序列是按时间顺序进行的一系列观察。任何时间序列数据都有以下组成部分: ref link

  • **级别:**如果是直线,则为系列的基线值。
  • **趋势:**系列随时间变化的可选且通常线性增加或减少的行为。
  • **季节性:**行为随时间的可选重复模式或周期。
  • **噪声:**模型无法解释的观测值的可选可变性。

大多数时间序列的另一个重要特征是,时间上接近的观测值往往是相关的(序列相关)。这种特征也被称为自相关,正如我们将在后面看到的,它构成了自回归综合移动平均( ARIMA )等传统时间序列建模技术的一个重要方面。

  • **平稳性:**当均值、方差和自相关性随时间恒定时,时间序列是平稳的,并且没有季节性或周期性模式。在使用任何基于线性回归的模型如 ARIMA(基于 Y 滞后值的回归)之前,使时间序列平稳是非常重要的。一个时间序列通常是平稳的,方法是将该序列与其自身进行差分。关于平稳性的两篇好文章— 1 、 2 。

由于以上所有的特点,时间序列建模涉及到的方法与常规的 ML 问题略有不同。这里的是解释主要区别的一个很好的链接。

这里的是深入研究时间序列预测建模技术的另一个好资源。

  • 时间序列交叉验证:(Ref)
    时间序列的交叉验证有点不同,因为人们不能在保留时间结构的同时随机混合一个文件夹中的值。随着随机化的进行,观测值之间的所有时间依赖关系都将丢失。这就是为什么我们必须在优化模型参数时使用更复杂的方法,例如“滚动交叉验证”。这个想法相当简单——我们从开始直到某个 t 的一小段时间序列上训练我们的模型,对下一个 t+n 步骤进行预测,并计算误差。然后,我们将我们的训练样本扩展到 t+n 值,从 t+n 直到t+2∫n进行预测,并继续移动我们的时间序列测试段,直到我们遇到最后一个可用的观测值。这可以使用*sklearn.model_selection's* TimeSeriesSplit模块来建立。我们将使用这种技术来计算验证集误差。

来源: Yorko/mlcourse.ai

比较我们的模型的基线模型

  • 短期提前一小时预测
**""" Error metrics for hour ahead forecasts when simply repeating last hour's values """** ***#* error_metrics(predicted_values, true_values) is a function that I *#* built to calculate the errors for a given model's predictions**_ = error_metrics(sdge_lin.loc[X_test.index.shift(-1, freq='H'), 'SDGE'], y_test)>> RMSE or Root mean squared error: 122.27
>> Variance score: 0.94
>> Mean Absolute Error: 99.23
>> Mean Absolute Percentage Error: 4.21 %
  • 未来约 8 个月的长期预测
**""" Error metrics on months ahead forecast when simply repeating last year's values """*****# the data is hourly and one year = 8760 hours***_ = error_metrics(sdge_lin.loc[X_test.index.shift(-8760, freq='H'), 'SDGE'], y_test)>> RMSE or Root mean squared error: 330.74
>> Variance score: 0.55
>> Mean Absolute Error: 224.89
>> Mean Absolute Percentage Error: 9.23 %

基准预测,其中能源消耗的预测值与去年相应的日、小时和月的值相同。

在能源预测领域,获得正确的每日最大需求更为重要,因为这可以决定电厂运营商是否需要启动调峰(主要是燃气)电厂。所以,也要计算误差。

*"""****Resampling both the y_test and predictions at a 24 hours period and using the max as the aggregate function****"""*_ = error_metrics(sdge_lin.loc[X_test.index.shift(-8760, freq='H'), 'SDGE'].resample('24h').max(), y_test.resample('24h').max())>> RMSE or Root mean squared error: 389.37
>> Variance score: 0.22
>> Mean Absolute Error: 264.44
>> Mean Absolute Percentage Error: 8.60 %

“我们现在已经准备好建立预测未来的模型了。”

注:通常用于时间序列预测的一些经典时间序列模型是自回归综合移动平均(ARIMA)、带外生回归量的季节自回归综合移动平均(SARIMAX)、带外生回归量的向量自回归移动平均(VARMAX)、简单指数平滑(SES)、霍尔特温特指数平滑(HWES)等等。你可以在 这篇 中找到更多关于各款车型的细节。在本帖中,我们将只尝试 SARIMAX,然后尝试传统的线性和非线性 ML 模型。

带滞后的简单回归模型(提前一小时预测)

那么,我们为什么还要考虑使用传统的 ML 回归模型进行时间序列预测呢?

  • 因为,在某些情况下,如销售预测或能源预测, y 变量强烈依赖于外部因素,如能源消耗情况下的温度。因此,与时间序列预测相比,它更像是一个回归问题,而且监督 ML 模型可以帮助我们在这种严重依赖外生变量的数据中找到更好的模式。
  • 像 SARIMAX 这样的传统时间序列模型无法处理多重季节性。它们还需要大量历史数据才能准确预测,并且在进行超参数调整时更加耗时。
  • 传统 ML 回归模型用于销售预测的用例请参见【3】。
  • 此外,这篇【4】论文证明了使用简单的基于回归的 ML 模型来预测电力需求是可能的,并且误差与更复杂的模型相当。

能源消耗值也可以预期依赖于其先前的滞后值,因为一个地区的能源消耗在接下来的几个小时内不应该有太大的变化,除非发生任何意外或不幸的事件。因此,我们将添加能耗的滞后值作为 X 参数,并检查我们是否可以使用过去的值进行更好的预测(除了我们已经添加的变量)。

***""" Adding max 24 lags; lag1 is the value of the energy consumption in the previous hour, lag2 is the value of energy consumption*
*2 hours before the current value and so on.****"""****# Creating the lag variables*****for** i **in** range(24):sdge1_lin['lag'+str(i+1)] = sdge1_lin['SDGE'].shift(i+1)***""" Since the first 24 values won't have any 24th lag, they will be NaN. So dropping the NaNs """***
lag_sdge = sdge1_lin.dropna()

请注意,我将小时划分为时间变量,将月份划分为季节,将工作日划分为非工作日或工作日。

有滞后的弹性净回归

对有滞后的数据进行拟合时,弹性网络回归模型的系数图。我们可以看到前一个小时的值有多重要。

plot_predvstrue_reg(elastic_net_lag.predict(X_test_lag), y_test_lag)

观察值与预测图

使用弹性网和随机森林回归分析观察到的与预测的能源需求值

**Error metrics for model Elastic net with all lags**
>> RMSE or Root mean squared error: 50.75
>> Variance score: 0.99
>> Mean Absolute Error: 37.36
>> Mean Absolute Percentage Error: 1.58 %

我们可以从图表和误差中看到,与基线相比,弹性网络模型在所有误差指标上都表现得更好。

  • RMSE 仅为 50.75 兆瓦,而基准型号为 122 兆瓦。
  • MAPE 也从 4.21%降至 1.58%。
  • 因此,这个模型表现非常好,但它有一个限制—我们只能用它来预测下一个小时的值。即它能准确预测的最大时间窗口是 1 小时。因此,如果这是应用情况,那么应该使用具有先前滞后值的弹性网络模型。

长期预测:用傅立叶级数处理多重季节性

  • 如前所述,像 SARIMAX 这样的传统时间序列模型无法处理多重季节性。
  • 有两种有趣的时间序列预测方法,称为 BATS 和 TBATS,能够模拟具有多个季节的时间序列,请查看链接。但是,它们的计算速度很慢,而使用傅立叶级数处理多个季节性的 SARIMAX 模型的性能与 TBATS 模型一样好。

这种特征转换背后的主要驱动点是,我们不能只将 0,1,2,…22,23 小时输入到模型中,因为我们需要让模型明白,0 和 23 小时实际上与 0 小时和 1 小时一样接近。工作日和年份也一样。

添加小时、年和周周期的傅立叶循环序列

m & n 可以是离散的。基于对训练集的一些试验和测试来选择 m=n=5。每日-> T = 24,每年-> T = 365.25,每周-> T= 7

***""" as said above the k terms for each yearly, weekly and daily seasonalities could be chosen by optimizing on the AIC values..*
*but after some research on energy consumption time series k= 5 was chosen for each seasonality """***add_fourier_terms(lag_sdge, year_k= 5, week_k=5 , day_k=5)***# Visualizing the new variables on week seasonality***_ = (1-lag_sdge.loc['01-01-2014':'01-09-2014', [col **for** col **in** lag_sdge **if** col.startswith('week')]]).sum(axis = 1).plot()

可视化新傅立叶变量对周的季节性。

从上面的图中,我们可以看到离散的工作日值是如何转换成更连续的变量模式的。每小时和每年的变量也是如此。

sdgecyc.head(2)

将日、周和年变量作为傅立叶级数添加的数据

上述傅立叶级数上的 SARIMAX 模型增加了数据集

  • 用先前时间的相同序列的值计算的时间序列观测值的相关性被称为序列相关,或自相关(ACF)。它用于确定 ARIMA(p,d,q)模型的移动平均(MA 或 q)项。
  • 偏自相关(PACF)是时间序列中的观测值与先前时间步长的观测值之间关系的总结,其中插入的观测值之间的关系已被移除。它用于确定 ARIMA(p,d,q)模型的自回归(AR 或 p)项。
  • ARIMA(p,d,q)中的 d 是使时间序列平稳所需的差分次数。
  • SARIMAX 是 ARIMA 的扩展,用于处理季节性项(S)和外生变量(X)。SARIMAX 模型的基本架构由 SARIMAX(p,D,q)x(P,D,Q,s)给出,其中 P,D,Q 如上文所定义,而(P,D,Q,s)分别是 AR 参数、差异、MA 参数和周期的模型的季节性组件。s 是一个整数,表示周期(季节中的周期数),对于季度数据,通常为 4;对于月度数据,通常为 12。默认情况下没有季节性影响。

SARIMAX 模型接受许多输入,需要进行一些调整才能选择最佳的模型参数。 *pmdarima* package 的 *auto_arima* 模块自动完成这项任务,并通过接受一些输入范围给我们提供最佳模型,类似于 gridsearchcv。

我们可以从分位数和直方图中看出拟合度很好,但不是很好。右下角的图,也称为 ACF 图,显示残差不自相关。任何自相关都意味着在模型中没有解释的残差中存在某种模式。

测试集上的 SARIMAX 预测仅显示到第一周,因为该模型无法很好地预测此后的情况。

**Error metrics for model SARIMAX(2,1,1)x(1,0,1,24) with Fourier terms 1 week ahead forecast on test set**
RMSE or Root mean squared error: 150.46
Variance score: 0.68
Mean Absolute Error: 103.46
Mean Absolute Percentage Error: 5.33 %
  • 我们看到,第一周的预测非常好,但即使在第一周结束时,预测性能也会下降,置信区间值会变得更大,超出能耗值的范围。因此,SARIMAX 模型无法捕捉长期趋势,但在 1 周预测中表现良好。
  • 前面没有使用(dynamic=True)为 SARIMAX 模型计算 1 小时提前预测的误差,因为我们使用滞后变量对 1 小时提前预测使用弹性网络回归得到了极好的结果,并且它比 SARIMAX 拟合速度快得多。

FB 先知

让我们尝试使用 FBProphet 解决我们的问题。FBProphet 提供了一个分解回归模型,它是可扩展的,并且可以用可解释的参数进行配置。Prophet 将预测问题框定为曲线拟合练习,而不是明确地查看时间序列内每个观察值的基于时间的相关性。与 SARIMAX 类似,我们也可以向模型中添加额外的回归项,如温度数据。(参考链接 1 、链接 2 、链接 3 )

其核心是,Prophet 是一个附加模型,包含以下组件:

y(t)=g(t)+s(t)+h(t)+ϵₜy(t)=g(t)+s(t)+h(t)+ϵₜ

***【g(t)***模型趋势
s(t) 模型季节性与傅立叶级数
h(t) 模型节假日或大型活动的影响
ϵₜ 代表不可约的误差项

  • 在使用 Prophet 时,仅使用“SDGE”、“HourlyDryBulbTemperature”、“累计 _AC_kW”、“非工作 _ 工作”列,因为 Prophet 与 SARIMAX 不同,可以很好地处理多个季节。 所以,我们不需要在傅立叶项中单独传递。
  • FB Prophet 可以通过假日功能传递,但是由于我们已经在‘non _ working _ working’列中捕获了假日和周末,所以我们不会将单独的假日列表传递给 Prophet。

FB Prophet 对训练集和测试集的预测

我们数据的 FB Prophet 分解模型。它似乎很好地模拟了我们数据的多重季节性——每天、每周和每年。在最底部的图中,额外的回归变量附加项包括温度、non_working_working 和 cum_AC_kW 变量。我们以波动的形式看到温度和工作日的影响,而累计 AC kW 的总体影响是能源的下降趋势(正如预期的那样,因为客户站点安装的光伏越多,对电网的需求就越低)。如果我们将这一趋势与第一行图的整体趋势相结合,那么整体趋势会下降。

**Error metrics for FB Prophet w/ auto seasonality 1 week ahead**
RMSE or Root mean squared error: 203.21
Variance score: 0.76
Mean Absolute Error: 164.76
Mean Absolute Percentage Error: 7.66 %**Error metrics for FB Prophet w/ auto seasonality 8 months ahead**
RMSE or Root mean squared error: 262.74
Variance score: 0.72
Mean Absolute Error: 201.06
Mean Absolute Percentage Error: 8.55 %

因此,尽管该模型的误差高于其他模型,但无论是一周预测还是数月预测,看起来 FB Prophet 已经很好地捕捉到了我们数据的多重季节性和趋势。

使用傅立叶项的回归模型(长期预测)

随机森林和弹性净回归(长期预测)

这里我只提一下随机森林的错误。弹性净回归在长期预测中表现不佳。

**Error metrics for Tuned Random forest with fourier terms**
RMSE or Root mean squared error: 196.99
Variance score: 0.84
Mean Absolute Error: 137.41
Mean Absolute Percentage Error: 5.73 %
  • 添加傅立叶项后,随机森林表现良好。它很好地捕捉了多重季节性,并且给出了仅 5.76%的 MAPE,而基线 MAPE 为 9.23%。
  • 弹性网络回归没有随机森林那样捕捉到更高的能耗值。
  • Random forest 更好的性能为在数据上尝试基于树的 XGBoost 模型铺平了道路。

带傅立叶项的 XGBoost(长期预测)

  • XGBoost(极限梯度增强)属于增强算法家族,其核心使用梯度增强(GBM)框架。它是一个优化的分布式梯度增强库。
  • 众所周知,XGBoost 提供了比其他机器学习算法更好的解决方案。它通常不用于时间序列,特别是如果使用的基础是树木,因为很难捕捉树木的趋势,但由于我们的数据没有非常显著的趋势,而且由于它具有多个季节性(使用傅立叶级数建模)并显著依赖于外部变量,我们可以尝试 XGboost,看看它在能源消耗的时间序列数据上的表现如何。
**Error metrics for Tuned XGBoost with Fourier terms**
RMSE or Root mean squared error: 172.21
Variance score: 0.88
Mean Absolute Error: 121.19
Mean Absolute Percentage Error: 5.08 %

XGBoost 预测值和真实观察值一起绘制

XGBoost 预测值与真实观察值

XG 增强参数重要性。正如所料,温度是最重要的预测因素。

  • 整个模型在大约 2 分钟内被调整和适应。
  • 它似乎已经很好地学习了数据模式和多个季节。与 9.23 %的基线相比,约 8 个月的预测误差仅为 5.08%。此外,与基线的 55%相比,R2 拟合度为 88%。

集合模型(XGBoost + FB Prophet 趋势,长期预测)

为什么要考虑这个?

  • 如前所述,要对时间序列数据建模,它需要是静态的。因此,理想的情况是取消数据趋势,然后将其输入 ML 模型,然后将趋势添加到预测结果中。尽管如此,由于 2014 年至 2018 年的能源消耗数据具有非常弱的趋势,并且傅立叶项很好地处理了多个季节性,因此在没有消除趋势的情况下获得了上述良好结果。
  • 或者,可以使用 FB Prophet 对总体数据趋势以及 cum_AC_kW 的影响(即迄今为止的累计光伏安装量)进行建模,然后与 XGBoost 的预测进行合并。任何像 XGBoost 这样的基于树的回归模型都不能轻松地处理像 cum_AC_kW 这样的 X 变量,因为它是一个不断增长的变量,并且测试数据总是具有模型在训练集中看不到的更高的量值。
  • 我已经从 FB Prophet 模型中提取了趋势和 cum_AC_kW 对能源的影响,并从我们的主数据框架中减去了这两个分量和所有傅立叶项。然后,这种消除趋势的能耗数据被传递到 XGBoost 模型,并将 XGBoost 预测结果添加回总趋势,以获得最终预测。

下面是来自我们之前训练的 FBProphet 模型的 cum_AC_kw 的趋势和效果。

来自 FBProphet 的趋势信息

我们将采用以下架构来创建我们的新模型:

XgBoost + FBProphet 趋势

XGBoost + FBProphet 预测值与实际值的比较

XGBoost + FBProphet 预测值与实际值的比较

**Error metrics for XGBoost with detrend Prophet, Fourier terms**
RMSE or Root mean squared error: 212.97
Variance score: 0.81
Mean Absolute Error: 170.77
Mean Absolute Percentage Error: 7.30 %
  • 由于 FB Prophet 高估了趋势和 cum_AC_kW 对能耗的影响,特别是在时间尺度的末尾,组合模型的表现比单独的 XGBoost 差,从上面 forecast . trend+forecast . cum _ AC _ kW 的图中可以看出,该图显示了末尾的突然下降。这似乎会导致能源消耗预测不足,并影响总体结果。但是,与基线相比,该模型的表现仍然很好,由于上面讨论的原因,就稳定性而言,该模型是比单独使用 XGboost 更好的时间序列模型。

结论

  • 尝试了不同的模型来预测加利福尼亚州圣地亚哥煤气和电力(SDGE)公用事业区每小时的能源需求,以兆瓦为单位。
  • 能源消耗高度依赖于外部温度,并具有强烈的多重季节性——每天、每周和每年。该地区越来越多的 PV(光伏)装置( cum_AC_kW )似乎带来了能源消耗的下降趋势,因为客户设施中更多的可再生能源意味着电力公司的负荷减少。请注意,可能有其他因素导致这种下降趋势,如客户设施中的储能装置、家用和商用设备的电力效率提高、人们越来越意识到它们的使用(道德上或通过公用事业激励)等。
  • 捕捉趋势的最佳方式是让模型在很长一段时间内学习趋势,这是上述所有因素的组合,也许更多。季节性是预测一个地区能源消耗的重要组成部分,因此正确预测这一部分对于提高模型的性能也至关重要(这是通过使用傅立叶级数实现的)。
  • 测试集上提前一小时预测的误差项

测试集上的误差项短期提前一小时预测

  • 测试集上未来几个月预测的误差项

  • 具有傅立叶项的 XGBoost 模型表现非常好,预测了未来 8 个月的预测窗口。对于具有多个季节性的每小时数据,这是一个相当令人印象深刻的结果。
  • 对于长期预测,大多数模型的表现优于基线持续性模型,最佳模型( XGBoost )给出了 5.08%的 MAPE,而测试集的基线误差为 9.23%。RMSE、R2 和 MAE 值也大大低于基线模型。例如,RMSE 与基线模型的差异几乎是 160 MW,这是非常显著的。为了帮助人们更好地理解这一点,燃气联合循环电厂的平均规模是500 兆瓦。
  • FB Prophet 在识别数据的趋势和多重季节性方面做得非常好。它可以与 XGBoost 配合使用,从而获得更可靠的长期预测。

谢谢!如果您有任何问题或想要提出任何改进或更正的建议,请随时联系我。

节约能源,拯救地球。

Streamlit 会导致 Flask 灭绝吗?

原文:https://towardsdatascience.com/part-2-will-streamlit-cause-the-extinction-of-flask-395d282296ed?source=collection_archive---------22-----------------------

可能对于机器学习(ML)和深度学习(DL)来说。对于其他全栈应用,大概不会!

我们还没有遇到一个基于 ML 或 DL 的 Flask 的微服务不能被重构为Streamlit服务。

挑战在于保持精简微服务的规模,只需替换 2 到 3 个基于 Flask 的微服务。

烧瓶熄灭?

我曾在 20 多家公司工作或咨询过,我很幸运能在两家大公司工作,这两家公司非常有远见,不断改进,并把创新作为公司战略的一个组成部分。

我为一家公司工作,该公司的管理层欣赏新的开源软件包的快速发展,并让我评估它们是否可能被采用。

目前,我正在将 Flask 微服务重构为 Streamlit 微服务。这些重构的原型,如果被证明在维护费用上更好(并通过我们的测试金字塔),就允许投入生产。

通过更换工作烧瓶微服,我们违反了 【不破,不修】 教义。

我认为用 Streamlit代替未破的*非常具有前瞻性和创新性(不过话说回来,我也很偏颇)。时间会证明这是否是一种进步。*****

较早的帖子被重新访问

在早先的帖子中,我用简单的 *hello World 比较了烧瓶流线举例。我们发现 Flask 需要 7 行代码,而 Streamlit 需要两行代码。***

***** [## Streamlit 会杀死 Flask 吗?

好吧,标题有点戏剧性。怎么样… Streamlit 将取代许多基于烧瓶的应用程序。

medium.com](https://medium.com/swlh/part-1-will-streamlit-kill-off-flask-5ecd75f879c8)

我将两个微服务都放在一个 Docker 容器中,其环境是 Python 3.7 。我使用 Docker 以便我们可以将烧瓶Streamlit、进行比较,并且我的示例可以在您的平台上轻松复制。

[## 使用 Docker 容器作为开发机器

我们是如何做到的,我们学到了什么

medium.com](https://medium.com/rate-engineering/using-docker-containers-as-development-machines-4de8199fc662)

我们发现为烧瓶或 **Streamlit 创建 Docker 容器的努力没有差别。**任何一个都可以作为本地 web 服务或您的云提供商的生产微服务。

注意:在本文中,我没有使用生产服务器,比如 Heroku

概述

我们将一起旅行,创建一个比 Hello-world 更复杂的微服务!。 FlaskStreamlit 将比较具有输入、 pandas dataframe 显示和绘图的 web-app 实现。

我们将再次使用 Docker ,以便我们可以将 Flask 与 **Streamlit、**进行比较,并且可以在您的平台上轻松复制示例。

引入烧瓶

当建立网站时,你应该有一个健壮的框架来处理所有类型的功能。在 Python 全栈软件工程师中最受欢迎的微服务框架之一是 Flask

烧瓶的一些参考资料包括:

[## Flask —在 Web 上托管您的 Python 机器学习模型

了解如何使用 Python Flask 将您的机器学习模型转化为业务

medium.com](https://medium.com/fintechexplained/flask-host-your-python-machine-learning-model-on-web-b598151886d)

可以把 Flask 想象成一个软件包的集合,它可以帮助你轻松地创建一个 web 应用程序。这些组件可以被组装和进一步扩展。

[## 烧瓶大型教程,第一部分:你好,世界!

这是我将记录我用 Python 编写 web 应用程序的经历的系列文章的第一篇…

blog.miguelgrinberg.com](https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world-legacy) [## 处理 Flask 中的传入请求数据

在任何 web 应用程序中,您都必须处理来自用户的请求数据。Flask 和任何其他 web 框架一样,允许…

scotch.io](https://scotch.io/bar-talk/processing-incoming-request-data-in-flask)

介绍 Streamlit

Streamlit 是一个开源的 Python 框架,使我们能够开发和部署基于 web 的应用程序。

[## Streamlit -构建定制 ML 工具的最快方法。

Streamlit 是一个面向机器学习和数据科学团队的开源应用框架。在…中创建漂亮的数据应用程序

www.streamlit.io](https://www.streamlit.io) [## 如何为数据科学家使用简单的 Python 编写 Web 应用?

无需了解任何 web 框架,即可轻松将您的数据科学项目转换为酷炫的应用程序

towardsdatascience.com](/how-to-write-web-apps-using-simple-python-for-data-scientists-a227a1a01582)

Web 框架很难学。为了一些看似简单的事情,我仍然会对所有的 HTML、CSS 和 Javascript 感到困惑。

在本文中,我们会继续发现,我们需要成为一名称职的 Python 全栈 Flask 软件工程师。我们需要知道如何使用 JavascriptHTML,wt forms**,**和/或Bootstrap和/或 Flask-RESTful 和/或(非常非常多的打包机会)。

我发现烧瓶是一个健壮的框架。所有的扩展使它更加强大。更重要的是,它通过提供适合您的包扩展来适应您的编程风格。

一个好的全栈烧瓶程序员会有多年的经验。然而,一个优秀的 Streamlit 黑客(就像机器学习科学家)需要数周的经验来设计、开发和部署一个生产就绪的基于网络的仪表板。

如果我们是Python**Streamlit 机器学习或者深度学习科学家,我们做不是需要知道 JavascriptHTML 、 **CSS 等..、和堆栈中不同的 POST/GET URL 包。相反,我们的软件栈由 Streamlit ( 和可能是 Docker) 组成。就是这样!

** [## 全栈宣告死亡

欢迎 2020 堆栈

medium.com](https://medium.com/better-programming/2020-001-full-stack-pronounced-dead-355d7f78e733)

结果是专业化。前端开发人员处理 HTML、CSS 和 JavaScript。后端开发人员处理主机操作系统、HTTP 服务器和数据库。精通这两种语言的开发人员被称为全栈开发人员。

专业化是一件好事。直到它不是。一方面,这意味着团队可以并行工作以缩短开发周期。另一方面,这意味着我们必须额外努力沟通初始需求和变更单规范,否则我们将冒着失去并行工作成果的风险。

因此,拥有一个全栈开发团队,没有可区分的前端/后端组,似乎是一个好主意。

更快的满足感(再次)

在您选择的目录中完成以下操作:

[git clone https://github.com/bcottman/webApps.git](https://github.com/bcottman/webApps.git)

在另一篇博客中,我们创建了包含所有代码的/webApps目录树。在不同于上次的不同父目录中使用git clone,以获得更新(或者使用相同的父目录并覆盖您对原始代码所做的任何更改)。或者…我将让您决定如何管理您的文件系统

1.输入和数据帧显示的 Flask 实现

对于我们的 Flask 微服务的第一个实现,我将显示一个熊猫数据帧。

来自浏览器 URL 的dataset参数被返回并分配给运行在服务器上的dataviewer1.py中的dataset_name。这是服务器代码中非常基本的变量设置(即[http://localhost:5000/show?dataset=Airq](http://localhost:5000/show?dataset=Airq).) )。.)

import pandas as pd
from pydataset import datafrom flask import Flaskapp = Flask(__name__)
app.debug = True@app.route('/show', methods=['GET'])
def dataViewer_1():dataset_name = request.args.get('dataset')if dataset_name == None:dataset_name = 'Aids2'  #default if no arg passed if type(data(dataset_name)) != pd.core.frame.DataFrame:return('Bad dataset name:{}'.format(dataset_name)) return data(dataset_name).to_html(header="true", table_id="table")if __name__ == "__main__":app.run()################# requirements.txt file
Flask>=1.1.1
pandas 
pydataset

输出[=>]:

使用 df.to_html 部分显示 Airq 数据集

2.用 HTML 实现熊猫数据帧显示

感谢https://stack overflow . com/questions/22180993/pandas-data frame-display-on-a-网页/22233851 ,免去了我学习 HTMLBootstrap (毕竟我是一个没有耐心的 ML 科学家)。 Bootstrap烧瓶提供的大量扩展之一。

## dataViewer-2.py
import pandas as pd
from pydataset import data
from flask import Flask, request, render_template
from flask_bootstrap import Bootstrapapp = Flask(__name__)
app.debug = True
Bootstrap(app)@app.route('/show', methods=['GET'])
def dataViewer_2():dataset_name = request.args.get('dataset')if dataset_name == None:dataset_name = 'Aids2' if type(data(dataset_name)) != pd.core.frame.DataFrame:return('Bad dataset name:{}'.format(dataset_name)) df = data(dataset_name) return render_template("df.html", name=dataset_name, data=df.to_html())if __name__ == "__main__":app.run()### df.html{% extends "bootstrap/base.html" %}
{% block content %}
<h1>{{name}}</h1>
{{data | safe}}
{% endblock %}################# requirements.txt file
Flask>=1.1.1
pandas 
pydataset
flask_bootstrapoutput[=>]:

使用 HTML 和 bootstrap/base.html 部分显示 Airq 数据集显示

使用我们自己的 HTML 模板,我们可以定制网页布局。

我将留给读者用 CSS 或任何你可能使用的 Flask 扩展来进一步定制。

3.抵御 CSRF 攻击的 Flask 实现

我将使用 wtform 包来抵御跨站请求伪造 (CSRF)攻击。我们将使用WTForm app.config['SECRET_KEY'].您控制台中的命令是:

$  python -c 'import os; print(os.urandom(16))'

我将生成的密钥放在我的dataView-3.py文件的顶部。

from flask import Flaskapp = Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = '\xbfx\x02\xf7\xeao\ro\rp&Q\xa1\xbdV\xd9'#<more code...>
if __name__ == '__main__':app.run(debug=True, host='0.0.0.0')

我没有在@app.route I .结果是:

输出[=>]:

Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again

3.将所有这些与 pandas 数据帧图的 Flask 实现放在一起。

# !/usr/bin/env python
# -*- coding: utf-8 -*-__author__ = "Bruce_H_Cottman"
__license__ = "MIT License"import pandas as pd
from pydataset import data
from flask import Flask, request, render_template, session
from flask_bootstrap import Bootstrap
from bokeh.plotting import Figure
from bokeh.models import ColumnDataSource
from bokeh.embed import components
from bokeh.resources import INLINE
from bokeh.util.string import encode_utf8
from bokeh.palettes import Spectral11app = Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = '\xbfx\x02\xf7\xeao\ro\rp&Q\xa1\xbdV\xd9'
Bootstrap(app)@app.route('/show', methods=['GET'])
def dataViewer():dataset_name = request.args.get('dataset')if dataset_name == None:dataset_name = 'Aids2'if type(data(dataset_name)) != pd.core.frame.DataFrame:return('Bad dataset name:{}'.format(dataset_name))df = data(dataset_name)session['dataset_name'] = dataset_namereturn render_template("df.html", name=dataset_name, data=df.to_html())@app.route('/plot')
def dataViewer_4():dataset_name = session['dataset_name']if dataset_name == None:dataset_name = 'Aids2'if type(data(dataset_name)) != pd.core.frame.DataFrame:return('Bad dataset name:{}'.format(dataset_name))if type(data(dataset_name)) != pd.core.frame.DataFrame:return('Bad dataset name:{}'.format(dataset_name))# get dframe by namedf = data(dataset_name)# Create a ColumnDataSource objectbp_df = ColumnDataSource(df)# Create  plot as a bokeh.figure objectplot = Figure(height=400,width=400,title=dataset_name,)x_ax = [str(i) for i in range(df.shape[0])]palette_ = Spectral11[0:len(df.columns)]for n, cname in enumerate(df.columns):plot.line(x=x_ax, y=list(df[cname].values), color=palette_[n], legend='line')# grab the static resourcesjs_resources = INLINE.render_js()css_resources = INLINE.render_css()# render templatescript, div = components(plot)html = render_template('index_.html',plot_script=script,plot_div=div,js_resources=js_resources,css_resources=css_resources,)return encode_utf8(html)if __name__ == "__main__":app.run(debug=True, host='0.0.0.0')### df.html{% extends "bootstrap/base.html" %}
{% block content %}
<h1>{{name}}</h1>
{{data | safe}}
{% endblock %}################# index_.html
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta http-equiv="content-type" content="text/html; charset=utf-8"><title>Embed Demo</title>{{ js_resources|indent(4)|safe }}{{ css_resources|indent(4)|safe }}{{ plot_script|indent(4)|safe }}</head><body>{{ plot_div|indent(4)|safe }}</body>
</html>################# requirements.txt file
Flask>=1.1.1
flask_bootstrap
pandas
bokeh
pydataset

输出[=>]:

散景数据集 Airq 图嵌入烧瓶

我使用工具栏中的散景的缩放来放大数据集中的线条。我用散景创建很棒的交互式图形,避免直接使用 Javascript

简化dataViewer.py的实施

在这个dataViewer.py,的实现中,我将使用 Streamlit 。我真的不需要把这个实现分成几个步骤,因为这个dataViewer.py只是 python ,一些 Streamlit 函数和 pandas 包。

import streamlit as st
import pandas as pd
from pydataset import datadf_data = data().sort_values('dataset_id').reset_index(drop=True)
st.dataframe(df_data)  #choicesoption = st.selectbox('select a dataset do you like best?', df_data['dataset_id'])dataset = data(option)if isinstance(dataset, (pd.core.frame.DataFrame,   pd.core.series.Series)):st.dataframe(dataset)st.line_chart(dataset)

输出[=>]:

显示和绘制 airq 的简化选择。

Streamlit 实现需要引用包的 Python 代码的 10 个语句行: streamlitpandaspydataset

pydataset 包含超过 750 个数据集。

在您的实现中,dataset_ids(数据集名称)在显示顶部的描述框和下拉选择框中按字母升序排序。

请注意当您单击选择框时,它是如何展开的。

您选择的数据集显示在从上往下数的第三个框中。 Streamlit 的一个特点是数据集的呈现是动态的,每一列的值都是升序或降序排序。此外,如果显示框的宽度或高度不足以显示所有的列或行,则它会在水平轴或垂直轴上滚动。

在最后一个框中,我们可以看到数据集的折线图。每行对应于数据集的一个数字列(要素)。

在这个 Streamlit 微服务的实际现场实现中(与这里显示的静态截图相反),您可以水平或垂直拖动来改变水平或垂直比例。您也可以放大和缩小来更改大小。

Streamlit 的掩护下,在 JavascriptHTML 、 **CSS、JSON、**的网页的选定端口上输出,并进行 web 通信。虽然我已经放弃了一些底层控制,但我已经获得了一个将 python 脚本转换成全功能 web 应用程序的强大机制。

在许多方面,我们在这里比较的东西类似于使用第四代高级语言( Streamlit )来机器汇编( Flask、 JavascriptHTMLCSS、JSON、post/get 等)。).

我将把它作为一个编程练习,让您扩展这个实现,为不同图表的选择提供一个选择框。

流线型dataView.py in Docker Container

Dockerfile…

**FROM** python:3.7
#EXPOSE 8501
**WORKDIR /**dataViewer
**COPY** requirements.txt .**/**requirements.txt
**RUN** pip3 install **-**r requirements.txt
**COPY** . .
**CMD** streamlit run dataViewer.py

要构建容器…

$ docker build -f Dockerfile -t dataviewer-streamlit:latest ..

其中requirements.txt是…

streamlit
pandas
pydataset

要运行容器…

$ docker run -p 8501:8501 dataviewer-streamlit &

码头集装箱与dataViewer.py and HelloWorld.py are的区别在于requirements.txt.中的集装箱名称和条目

Docker 的问题

如果你得到任何这些信息,你需要启动或重启 Docker 。我在一台 Mac 上,所以我只是重启Docker桌面。

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. 
Is the docker daemon running?.**<or>**ERRO[0050] error waiting for container: EOF

通过在:5000.港运行不同的集装箱,你会遇到这个很难理解的问题

docker: Error response from daemon: pull access denied for 5000, repository does not exist or may require ‘docker login’: denied: requested access to the resource is denied.

修复如下所示,并在您的终端窗口中键入。(我确定还有更好的。)

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)# remove port assignments
  1. 找出占用您想要释放的端口号(例如5000)的进程 ID (PID)。(为您的操作系统确定合适的命令)
sudo lsof -i :5000

第二步。使用其<PID>.终止当前正在使用该端口的进程

sudo kill -9 <PID0> ... <PIDn>

摘要

在本文中,我们比较了基于 Flask- 的和基于 Streamlit- 的web 应用程序,使用了一个具有输入、交互式数据集显示和数据集数值列的折线图的示例。我们发现烧瓶需要大约 100 行代码流线型需要十行代码

我们发现创建烧瓶微服务至少需要知道如何使用 HTMLCSS

我们可以将两个微服务放在一个 Docker 容器中,该容器的环境是一个 Python rc(发布候选)。其中任何一个都可以用作本地 web 服务或您的云提供商的生产微服务。

参考

[## Streamlit 101:深入介绍

利用 Airbnb 数据深入了解 Streamlit

towardsdatascience.com](/streamlit-101-an-in-depth-introduction-fc8aad9492f2) [## 使用 Streamlit 将您的数据科学脚本转变为网站

展示你的数据科学/机器学习实验的发现可能很困难。而在过去,一个…

gilberttanner.com](https://gilberttanner.com/blog/turn-your-data-science-script-into-websites-with-streamlit) [## 如何为数据科学家使用简单的 Python 编写 Web 应用?

无需了解任何 web 框架,即可轻松将您的数据科学项目转换为酷炫的应用程序

towardsdatascience.co](/how-to-write-web-apps-using-simple-python-for-data-scientists-a227a1a01582) [## 烧瓶大型教程第十九部分:Docker 容器上的部署

这是 Flask 大型教程系列的第 19 部分,其中我将把微博部署到…

blog.miguelgrinberg.com](https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xix-deployment-on-docker-containers) [## Python 绘图 API:通过 flask API 展示您的科学 python 绘图

在我作为数据科学家的日常工作中,我经常需要将相对复杂的情节集成到后台…

towardsdatascience.com](/python-plotting-api-expose-your-scientific-python-plots-through-a-flask-api-31ec7555c4a8)

展望未来

在第 3 部分中,我们将一起开发一个更复杂的微服务,它有一个完整的机器学习管道。在第 3 部分中,我们将通过使用 Streamlit 来避免成为全栈 Flask 开发者。

在以后的文章中,我将比较 DashStreamlit。

[## 部署

若要共享 Dash 应用程序,您需要

dash.plot.ly](https://dash.plot.ly/deployment)

Dash Enterprise 是 Plotly 的商业产品,用于在您公司的服务器或 AWS、谷歌云或 Azure 上部署 Dash 应用程序。它提供了一个企业范围的 Dash 应用程序门户、基于 git 的简单部署、自动 URL 命名空间、内置 SSL 支持、LDAP 认证等等。

公平地说,脸书等人还不能将 Streamlit 用于他们面向公众的网站,然而,正如我们将在第 3 部分中看到的,作为一个大部分时间都在用 Python 库编码的机器学习科学家, Streamlit 提供了一个简单的 Python API。

我能够在 4 天内设计、编码、测试、部署一个基于 T21 的 ML 仪表板。我的首席技术官把它放在了他的桌面上。(好吧,我是应他的要求做的。)他喜欢。

我们的全栈团队使用 Flask 需要大约三周时间(使用 Django 需要一周时间)来将新的 ML 应用程序投入生产。

Streamlit 不需要你学习几个新的范式和语言,比如 HTMLCSSJSONJavaScript。它不需要你知道使用什么烧瓶分机。我应该使用自举还是 WTForms 还是其他什么或者它们的组合?

我已经在烧瓶中编程几个月了。我现在理解了一个全栈程序员在生产一个基于烧瓶的微服务时所使用的大量知识。我敬畏他们。

如果你是一个 Streamlit 黑客(像我一样),你需要而不是知道 JavascriptHTMLCSS、JSON ,以及栈中不同的 POST/GET URL 包。相反,你的筹码将由 Streamlit ( 和也许是 Docker) 组成。就是这样!

我希望你发现 Streamlit 上的这篇博客很有用。我期待着在这方面写一篇博客,我希望你也是!*******

第 2 部分—又一个面具检测器… (OpenCV 空间人工智能竞赛之旅)

原文:https://towardsdatascience.com/part-2-yet-another-face-mask-detector-opencv-spatial-ai-competition-journey-91dfaf96c6e8?source=collection_archive---------27-----------------------

来自 Pexels 的古斯塔沃·福林对视频进行面具检测

盲人社交距离反馈系统中不同面具检测模型的比较。

本文是系列文章的一部分,我将记录我在 OpenCV 空间竞赛中为盲人开发社交距离反馈系统的旅程。查看完整系列: 第一部 第二部

为什么要做口罩检测?

正如该系列的第一部分 中提到的,这个项目的目标是为盲人开发一个 反馈系统,帮助他们使用 OAK-D 保持与周围人的社交距离(顺便祝贺 Luxonis LLC 和 Satya Mallick 成功开展了【Kickstarter 活动!)。在这篇文章中,我将重点关注使用深度学习模型对周围人的检测,以便与这些人保持距离。

对用户周围的人的检测可以以多种方式来完成,一种选择可以是训练用于行人检测的模型,如在 这个库 中。另一个可能的选择是只检测脸部而不是检测整个身体。人脸检测模型的好处是,由于人脸的独特特征,即使不需要深度学习模型,也更容易检测人脸。例如,在本 OpenCV 教程 的 中,使用了基于 Haar 特征的级联分类器方法,即使在低计算设备中也能实时检测人脸。

然而,在这个特定的应用中,我们还想知道周围的人是否戴着面罩。然后,最好的选择将是仅使用一个检测人在哪里以及他们是否使用面罩的模型,即面罩检测器。

面罩检测器过多

由于当前疫情中面罩使用的增加,许多人已经开发了面罩检测系统。在 Github 中快速搜索“面具检测”会返回大约 700 个关于这个主题的知识库。同样,在 Youtube 中搜索相同的术语,会返回一个没完没了的视频列表,显示人脸检测模型的实现。

因此,有了这么多可用的例子,我希望很容易找到一个对深度为 ( OAK-D )的 OpenCV AI 套件来说足够快的例子,并且即使在现实生活环境中也具有良好的准确性。

但是,我们应该选择哪个人脸面具检测实例呢?

首先,我决定看看 **Github 中排名靠前的面具检测库。**下表总结了其中一些存储库中使用的数据集和模型列表。

面罩检测示例概述

正如可以观察到的,有两种主要的方法来执行人脸面具检测: 1 .人脸检测+对每个检测到的人脸进行面罩分类2。直接进行面罩检测。第一种方法可能具有更好的准确性,因为已经可用的人脸检测模型已经在成千上万的人脸图像中被训练。相比之下,如表中所示,人脸遮罩检测数据集具有较少的用于训练的图像,其中 AIZOOTech 数据集 具有较多的图像。

然而,大多数先前的人脸检测模型是在大多数情况下未被覆盖的人脸上训练的。由于这个原因,在脸部被遮罩覆盖的情况下,脸部检测模型可能会错过脸部的检测(如 pyimagesearch.com 中非常详细的文章 中所解释的)。

基于 OAK-D 的人脸面具检测

在分析前面提到的例子之前, Luxonis 的人已经提供了一个使用 OAK-D 进行面具检测的 演示。演示中的模型是一个在 Google Colab 中训练过的 MobileNetV2 (SSD)。

注:尽管不包括在演示中,他们也提供了另一个 Google Colab 脚本,用于训练一个 YOLOv3-tiny 模型用于人脸面具检测

要运行演示,需要安装 DepthAI Python 模块。正如 第一部 中提到的,Windows 版本仍然是实验性的。然而,最近这个过程已经被更新了,这样按照Luxonis 讨论中最后一个评论的 步骤安装库就容易多了。

然而,截至今天,面罩检测演示配置为与旧版本的 DepthAI 库一起工作。因此,我修改了演示程序,使其能够与当前版本的 DepthAI 一起工作,该程序可以在我的Github 资源库中找到。要运行该演示程序,需要按照前面的说明安装 DepthAI 库,并将 DepthAI 文件夹添加到系统的 PYTHONPATH 中。接下来,打开命令并运行以下命令:

git clone [https://github.com/ibaiGorordo/Social-Distance-Feedback.git](https://github.com/ibaiGorordo/Social-Distance-Feedback.git)
cd "Social-Distance-Feedback\Part 2 - Mask Detection"
python demo_mask_detector.py

demo_mask_detector.py 是一个脚本,用于配置 OAK-D 在 RGB 摄像机上执行人脸遮罩检测,并显示来自 OAK-D 的图像和检测。

下面的视频显示了 OAK-D 对 MobileNetV2 (SSD) 面罩检测模型的推理输出(使用 DepthAI 的 Google Colab sscript 训练)。

使用 OAK-D (SSD-MobileNetV2)的人脸面具检测

人脸面具检测模型在野外是如何表现的?

前面的例子类似于许多教程,以使用网络摄像头进行推理的例子结束。然而,我的系统的目标是在日常生活中使用,特别是在户外。因此,该系统在不同的光照条件下,甚至在周围有多人时,都应该是鲁棒的。

出于这个原因,我决定看看不同的人脸面具检测模型在更真实的环境中表现如何。出于这个目的,我使用了这段来自 pexels.com 的公开视频,记录了人们在夜市 中行走的场景。下面的视频显示了使用 DepthAI 的 Google Colab 脚本 训练的 SSD-MobileNetV2YOLOv3-tiny 模型的面罩检测的比较。 推理程序的代码可以在我的 Github 资源库这里找到

使用 SSD-MobileNetV2 和 YOLOv3-tiny 模型在真实生活环境中检测面具的比较

可以观察到, SSD-MobilenetV2 型号具有更高数量的检测,但结果是,更高数量的这些检测是错误的检测。即使将置信度阈值提高到 0.7(如上面的视频所示),SSD-MobilenetV2 型号仍然有大量的错误检测。

另一方面, YOLOv3-tiny 型号错过了一些人脸(特别是距离较远的人脸),但具有更稳定的检测,置信度阈值为 0.5。由于我们的应用程序只需要检测靠近用户的人(在 3 米或更近的距离),因此 YOLOv3-tiny 模型似乎是两个模型中最有希望的模型。

YOLOv4 呢?

最近,Alexey Bochkovskiy 展示了一个新 YOLO 版本(YOLOv4) ,它提供了比以前版本更高的性能。在下面的视频中,有一个来自 Mladen Zamanov 的例子,可以看出 YOLOv4 即使周围有很多人,也可以进行人脸面具检测。

YOLOv4 面罩检测推断由姆拉登扎马诺夫

在我们的应用程序中使用 YOLOv4 的问题是,为了将模型传递给 OAK-D ,需要将模型转换为**。blob 文件**将由 OAK-D 中的 Myriad X 运行。但是,为了转换模型,需要使用 OpenVINO toolkit 的模型优化器,目前官方支持到 YOLOv3 为止。

尽管由于 TNTWEN 的 库,可以使用最新 OpenVINO (2020.4)版本的模型优化器,但是 depthAI 模块仍然不支持它。结果,到今天为止,似乎 YOLOv4 无法用于内置摄像头的 OAK-D

无论如何,我决定试一试 YOLOv4,以防在不久的将来它可以用于 OAK-D。我特别关注新的 YOLOv4-tiny 版本,因为它应该更适合在计算能力较低的设备中进行实时推理(实际上 YOLOv4 的作者已经能够在 OAK-D 内部的同一芯片中运行 full YOLOv4 的修改版本,如此处所示)。

为此,我在 Google Colab 中使用这个脚本 **(下面的代码)**训练了 YOLOv4-tiny 模型,它是基于 DepthAI 的原始脚本。在同一个脚本中,我还添加了代码来检测我用来比较 SSD-MobileNetV2YOLOv3 的同一视频上的面具。

在下面的视频中,我展示了 YOLOv3-tinyYOLOv4-tiny 对 f ace mask 检测的结果比较。

使用 YOLOv4-tiny 和 YOLOv3-tiny 模型在真实生活环境中检测面具的比较

可以看出,两种模型的结果非常相似。在某些情况下, YOLOv4-tiny 能够检测到 YOLOv3-tiny 不能检测到的人脸,但总的来说结果几乎是一样的。

总之,我可能会继续使用 YOLOv3-tiny 进行面具检测,除非有新的支持 YOLOv4 。在下一部分中,我将重点关注深度和对象检测数据的组合。

这一部分和下一部分的所有代码都可以在我下面的库中找到:https://github.com/ibaiGorordo/Social-Distance-Feedback。

第 3/3 部分——预测我的半程马拉松完成时间,误差小于 45 秒。

原文:https://towardsdatascience.com/part-3-3-predicting-my-half-marathon-finish-time-with-less-than-45-seconds-error-9d43d6fadf01?source=collection_archive---------56-----------------------

跑步的机器学习——机器学习和结果。

坎德拉·温纳塔在 Unsplash 上的照片

这是教育结束时间预测系列的第 3 部分:

  • 第一部分—数据分析
  • 第二部分—狂妄分析
  • 第三部分——跑步者完成时间预测(你在这里)

在这篇文章中,我将向你展示我是如何在比赛开始前预测自己的完成时间(1:40:34),误差不到 45 秒。我们将利用第一部分的一些发现来:

  • 为我们的模型实现特性
  • 训练 5 个不同的模型来预测比赛中每个关卡的完成时间
  • 评估我们的结果

为什么我们需要机器学习

在第 2 部分中,我们得出结论,跑步者度量的平均值可以用来粗略估计他们的完成时间。随着我们使用更多的指标(特征)进行分组,预测会变得更好——如果我们使用第 5 组所有 28 岁男性的平均值,而不是只查看所有 28 岁男性,预测会变得更好。

然而,随着我们向分组依据添加更多指标(比如我们为第一站添加国家、城市和速度),每组中的跑步者数量会减少到一个点,即一组中可能只剩下一名跑步者。举个例子:

你认为有多少 28 岁的隆德男子在 23:20 内跑完第一个 5 公里?

只有一个。

机器学习

在机器学习中,我们将多维空间中的所有特征结合起来,并为我们的数据点拟合一个函数。我们称这个函数为模型。在训练阶段,模型从每个由特征(如年龄、性别等)表示的数据点(跑步者)中学习,以估计目标变量(完成时间)。模型如何学习取决于训练算法。

机器学习,图片来自 xkcd

数据是关于跑步者的信息。答案是跑步者的完成时间。搅拌就是机器学习算法。我们不停地搅拌,直到我们无法再提高预测的平均误差。

培训计划

我们的数据集分为训练集(80%的跑步者)和测试集(20%的跑步者)。我们不是随机分组,而是分组,这样每组中每个起跑组都有公平比例的选手。该模型在训练集上进行训练,然后在测试集上进行评估。模型预测的是跑步者的完成时间。

来自测试集的预测用于评估我们模型的性能。

我训练了五个模型来模拟现实,因为比赛中每个检查站都有更多的信息。见下文。

随着跑步者在比赛中的进步,更多的信息将会出现。我们逐渐使用更多的功能,并训练五个不同的模型—每个检查点一个。

请注意,这种类型的培训(仅使用当年的数据)在现实世界中是不可能的。它要求训练集跑步者在我们可以在测试集上进行预测之前进行比赛。理想情况下,我们应该有用于训练的历史数据,然后在最近的比赛中测试该模型。当然,一旦注册数据可用,我们可以根据所有数据进行训练,并对下一年进行预测——但这样做无法评估模型今天的实际表现。

预测误差和基线

预测是跑步者估计的完成时间。

为了评估模型给出的预测的准确性,我们将比较测试集中每个跑步者的完成时间预测和实际完成时间。例如,如果对某个特定赛跑者的预测是 2:00:00 ,但该赛跑者实际上在 1:59:00 完成,则误差为 60 秒。然而,为了使事情不那么一成不变,将使用基于百分比的指标,而不是绝对数字。在本例中,误差为 0.84%

平均误差计算为我们测试集中所有跑步者的 MAPE(平均绝对百分比误差)。通过与基线的平均误差进行比较,我们可以了解我们的模型有多好:

基线:使用预计平均步速的预测:

这是比赛中观众使用的默认预测方法。它是通过计算跑步者到目前为止的平均配速,然后乘以总距离来计算的。

我们的目标是超越基线,并有一个较小的平均误差。

特征

一般特征

跑步者注册的特征。随时可用。

使用的一般特征的解释。

5 公里配速特征

步伐特征。当跑步者通过 5 公里检查站时可用。

5 公里后使用的附加功能说明。

10、15、20 公里配速特征

同上,但分别为 10 公里、15 公里和 20 公里。我们还增加了一个功能,将跑步者的配速与普通精英跑步者的配速进行比较。该特征需要至少两个配速数据点(例如 5 公里和 10 公里),并用作跑步者和精英跑步者之间的相似性得分。

当达到一个以上的检查点时,我们还计算一个特征来测量与优秀跑步者速度曲线的相似性。

培养

使用上述特征和称为 RidgeRegression 的机器学习算法,我们训练该模型,教导它相对于我们的目标变量最小化多维空间中的数据点的 MSE(均方误差);结束时间。

我为什么要用 RidgeRegression?嗯,它训练起来很快,不需要很多高参数,而且很有效。鉴于我为这个项目设定的时间框架(在代码 19 的 1 周),我需要快速迭代来修复错误和尝试新功能。我尝试了一些不同的其他模型,发现 RidgeRegression 更胜一筹。我们让经过训练的模型在未用于训练的测试集上运行预测,并获得以下结果:

个人成绩

在我们看平均结果之前,让我们看看模型对我的个人结果的预测,让你对每个模型所扮演的角色有个概念。

奥斯卡·汉德马克的个人预测结果。我们的模型在所有情况下都优于基线(预计平均配速)。

结果

测试集中所有跑步者的结果(20%)。

我们设法将 10 和 15 公里检查站的预测平均绝对百分比误差提高了 50%以上!我们的模型在比赛前的预测误差最大,这是有意义的,因为我们在那一点上可以使用的信息较少。基线不能做赛前预测,所以我们认为这是无限百分比的改进。下图还显示了中间值(中线)、四分位数(方框顶部/底部)和(最小值/最大值)(晶须):

测试集错误。我们的训练模型(蓝色)在所有阶段都优于基线。10 公里和 15 公里检查站的改善最为显著。

丰富

  • 历史数据将允许我们跟踪回归的跑步者多年,并从他们以前的比赛中学习。它还可以让我们跟踪整个人群,从跑步的趋势变化中学习。随着时间的推移,我们是否已经成功地教育了跑步人群不要骄傲自大,以及这种影响的轨迹是什么?
  • 其他来源的数据,如 GPS 手表数据& Strava/Garmin history 将允许我们跟踪跑步者的训练,并将以前锻炼的结果作为我们模型的特征。
  • 更高分辨率的数据例如每公里而不是每五公里一次的检查点时间。这将允许我们的模型更频繁地提供新的预测,并更密切地监控自大和步伐变化。

学习

  • 带着手表跑步有助于你在比赛中调整自己的速度。
  • 设定目标!虽然跑步是一项身体运动,但也有很多心理因素。
  • 看你自己的数据!从中吸取教训。
  • 考虑你的年龄、性别和自大的风险。要知道,狂妄自大对年轻和年老的跑步者影响最大!
  • 计划你的比赛!查看精英跑步者的配速档案,并尝试以类似方式跑步。设定你的目标并向后计算你应该达到的检查点时间。

关于跑步的未来的简短说明

一个有趣的想法是考虑这样一种情况,我们可以在手表上运行这些模型,并在我们的手臂上每秒钟得到预测。这项技术现在已经存在,我很期待下一步会发生什么。同时,这是一个可怕的想法——这几乎就像一个骗局,有一个设备可以实时告诉你相对于你的能力,你跑得太快还是太慢。无论如何,我认为这将发展这项运动,并作为一种教育跑步者了解自己的方式。

下一步是什么

接下来我主要想做三件事。社区利益使这些成为可能。让我知道你接下来想看什么。

  • **赛事规划界面。**根据我在这个博客系列中的发现,创建一个小型用户界面应该是很容易的,跑步者可以在这个界面中输入他们的详细信息&完成时间目标,并接收个性化的提示和建议的配速配置。通过将 API 集成到时间跟踪软件中,可以在 UI 中可视化实时预测。
  • **史料。**纳入 goteborgsvarvet 的 20 年数据将大大改善结果。我很好奇,对于那些参加了多年的跑步者来说,我们能有多接近完美的表现。
  • 把这个给这个世界。通过添加一个更智能的结束时间预测器(就像这个),改善观众体验是微不足道的。我知道一些公司已经在这么做了,但是如果你知道有人可能感兴趣,请通过 oskar@backtick.se 联系我。

如果您错过了第 1 和第 2 部分,可以在这里找到:

  • 第一部分—数据分析
  • 第二部分——狂妄分析

第 3 部分:时间序列链

原文:https://towardsdatascience.com/part-3-time-series-chains-da281450abbf?source=collection_archive---------31-----------------------

用 STUMPY 进行时间序列预测的新方法

(图片由马克西姆·霍拉维尔提供)

整体大于部分之和

(图片由作者提供)

STUMPY 是一个强大且可扩展的 Python 库,用于现代时间序列分析,在其核心,有效地计算出一种叫做矩阵轮廓的东西。这个多部分系列的目标是解释什么是 matrix profile,以及如何开始利用 STUMPY 完成所有现代时间序列数据挖掘任务!

注:这些教程最初出现在 STUMPY 文档 中。

第 1 部分:矩阵轮廓图
第 2 部分: STUMPY 基础知识
第 3 部分:时间序列链
第 4 部分:语义分割
第 5 部分:用 STUMPY 快速近似矩阵轮廓图
第 6 部分:用于流式时间序列数据的矩阵轮廓图
第 7 部分:用 STUMPY 快速模式搜索 10: 发现多维时间序列模体
第 11 部分:用户引导的模体搜索
第 12 部分:机器学习的矩阵轮廓

用锚定时间序列链预测 Web 查询数据(ATSC)

之前,我们学习了什么是矩阵轮廓,以及如何使用 STUMPY 来发现任何时间序列数据中的主题(模式)和不一致(异常)。在这篇博客中,我们将把这些概念更进一步,探索从一个叫做时间序列链的矩阵剖面中衍生出来的东西。此示例改编自网络查询量案例研究,并利用了矩阵概况 VII 研究论文的主要内容。

入门指南

让我们导入加载、分析和绘制数据所需的包。

%matplotlib inlineimport pandas as pd
import numpy as np
import stumpy
from scipy.io import loadmat
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, FancyArrowPatch
import itertoolsplt.rcParams["figure.figsize"] = [20, 6]  # width, height
plt.rcParams['xtick.direction'] = 'out'

什么是时间序列链?

时间序列链可以非正式地认为是随着时间的推移向某个方向演变或漂移的主题。下图说明了时序主题(左)和时序链(右)之间的区别。

x = np.random.rand(20)
y = np.random.rand(20)
n = 10
motifs_x = 0.5 * np.ones(n) + np.random.uniform(-0.05, 0.05, n)
motifs_y = 0.5 * np.ones(n) + np.random.uniform(-0.05, 0.05, n)
sin_x = np.linspace(0, np.pi/2, n+1)
sin_y = np.sin(sin_x)/4
chains_x = 0.5 * np.ones(n+1) + 0.02 * np.arange(n+1)
chains_y = 0.5 * np.ones(n+1) + sin_y
fig, axes = plt.subplots(nrows=1, ncols=2)
axes[0].scatter(x, y, color='lightgrey')
axes[0].scatter(motifs_x, motifs_y, color='red')
axes[1].scatter(x, y, color='lightgrey')
axes[1].scatter(chains_x[0], chains_y[0], edgecolor='red', color='white')
axes[1].scatter(chains_x[1:n], chains_y[1:n], color='red')
axes[1].scatter(chains_x[n], chains_y[n], edgecolor='red', color='white', marker='*', s=200)

(图片由作者提供)

上面,我们将时间序列子序列可视化为高维空间中的点。左边显示的是一个时间序列主题,它可以被认为是一个近似柏拉图式理想的点的集合。相比之下,右边描绘的是一个时间序列链,它可以被认为是空间中的点的演化轨迹。在这里,开放的红色圆圈代表链中的第一个环节,锚。基序和链都具有这样的性质,即每个子序列都相对靠近其最近的邻居。然而,图案组(左)的直径也相对较小。相比之下,链中的点集(右)的直径比每个成员到其最近邻居的距离的平均值大得多,此外,链具有方向性的重要特性。例如,在一个基序的情况下,如果一个额外的成员被添加到基序集中,它的位置也将是接近柏拉图理想的某个地方,但是独立于前面的子序列。相比之下,在链的情况下,链的下一个成员的位置将在最后一个红色圆圈之后的某个地方,可能是开放的红星所在的位置。

一个简化的例子

改编自矩阵图 VII 文件,考虑以下时间序列:

47, 32, 1, 22, 2, 58, 3, 36, 4, -5, 5, 40

假设子序列长度为 1,两个子序列之间的距离就是它们之间的绝对差。明确地说,我们在这里做这些简单而病态的假设仅仅是为了说明;实际上,我们的目标是更长的子序列长度,并在我们的 STUMPY 应用中使用 z 归一化欧几里德距离。为了捕捉时间序列链的方向性,我们需要将左右最近邻信息存储到左(IL)和右(IR)矩阵轮廓索引中:

Index  Value  Left Index (IL)  Right Index (IR)
1         47              N/A                12
2         32                1                 8
3          1                2                 5
4         22                2                 8
5          2                3                 7
6         58                1                12
7          3                5                 9
8         36                2                12
9          4                7                11
10        –5                3                11
11         5                9                12
12        40                8               N/A

在这个垂直/转置表示中,index列显示了时间序列中每个子序列的位置,value列包含来自我们上面的时间序列的原始数字,IL列显示了左矩阵分布指数,IR是右矩阵分布指数。例如,IR[2] = 8表示index = 2(有value = 32)的右最近邻在index = 8(有value = 36)。同样,IL[3] = 2表示index = 3(有value = 1)的左最近邻在index = 2(有value = 32)。为了更好地可视化左/右矩阵轮廓索引,我们使用箭头将时间序列中的每个子序列与其左、右最近邻链接起来:

nearest_neighbors = np.array([[1,  47, np.nan,     12],[2,  32,      1,      8],[3,   1,      2,      5],[4,  22,      2,      8],[5,   2,      3,      7],[6,  58,      1,     12],[7,   3,      5,      9],[8,  36,      2,     12],[9,   4,      7,     11],[10, -5,      3,     11],[11,  5,      9,     12],[12, 40,      8, np.nan]])colors = [['C1', 'C1'],['C2', 'C5'],['C3', 'C5'],['C4', 'C4'],['C3', 'C2'],['C5', 'C3'],['C3', 'C2'],['C2', 'C1'],['C3', 'C2'],['C6', 'C1'],['C6', 'C2'],['C1', 'C1']]style="Simple, tail_width=0.5, head_width=6, head_length=8"
kw = dict(arrowstyle=style, connectionstyle="arc3, rad=-.5",)xs = np.arange(nearest_neighbors.shape[0]) + 1
ys = np.zeros(nearest_neighbors.shape[0])
plt.plot(xs, ys, "-o", markerfacecolor="None", markeredgecolor="None", linestyle="None")x0, x1, y0, y1 = plt.axis()
plot_margin = 5.0
plt.axis((x0 - plot_margin,x1 + plot_margin,y0 - plot_margin,y1 + plot_margin))
plt.axis('off')for x, y, nearest_neighbor, color in zip(xs, ys, nearest_neighbors, colors):plt.text(x, y, str(int(nearest_neighbor[1])), color="black", fontsize=20) # Plot right matrix profile indicesif not np.isnan(nearest_neighbor[3]):arrow = FancyArrowPatch((x, 0.5), (nearest_neighbor[3], 0.5), color=color[0], **kw)plt.gca().add_patch(arrow) # Plot left matrix profile indicesif not np.isnan(nearest_neighbor[2]):arrow = FancyArrowPatch((x, 0.0), (nearest_neighbor[2], 0.0), color=color[1], **kw)plt.gca().add_patch(arrow)

(图片由作者提供)

从一个数字指向其右最近邻的箭头(显示在时间序列上方的箭头)可以称为向前箭头,从一个数字指向其左最近邻的箭头(显示在时间序列下方的箭头)可以称为向后箭头。根据时间序列链的正式定义(参见矩阵剖面 VII 的详细定义和讨论),链中的每对连续子序列必须由向前箭头和向后箭头连接。敏锐的眼睛会发现,在我们的简化示例中,最长的链是:

nearest_neighbors = np.array([[1,  47, np.nan, np.nan],[2,  32, np.nan, np.nan],[3,   1, np.nan,      5],[4,  22, np.nan, np.nan],[5,   2,      3,      7],[6,  58, np.nan, np.nan],[7,   3,      5,      9],[8,  36, np.nan, np.nan],[9,   4,      7,     11],[10, -5, np.nan, np.nan],[11,  5,      9, np.nan],[12, 40, np.nan, np.nan]])colors = [['C1', 'C1'],['C2', 'C5'],['C3', 'C5'],['C4', 'C4'],['C3', 'C2'],['C5', 'C3'],['C3', 'C2'],['C2', 'C1'],['C3', 'C2'],['C6', 'C1'],['C6', 'C2'],['C1', 'C1']]style="Simple, tail_width=0.5, head_width=6, head_length=8"
kw = dict(arrowstyle=style, connectionstyle="arc3, rad=-.5",)xs = np.arange(nearest_neighbors.shape[0]) + 1
ys = np.zeros(nearest_neighbors.shape[0])
plt.plot(xs, ys, "-o", markerfacecolor="None", markeredgecolor="None", linestyle="None")x0, x1, y0, y1 = plt.axis()
plot_margin = 5.0
plt.axis((x0 - plot_margin,x1 + plot_margin,y0 - plot_margin,y1 + plot_margin))
plt.axis('off')for x, y, nearest_neighbor, color in zip(xs, ys, nearest_neighbors, colors):plt.text(x, y, str(int(nearest_neighbor[1])), color="black", fontsize=20) # Plot right matrix profile indicesif not np.isnan(nearest_neighbor[3]):arrow = FancyArrowPatch((x, 0.5), (nearest_neighbor[3], 0.5), color=color[0], **kw)plt.gca().add_patch(arrow) # Plot left matrix profile indicesif not np.isnan(nearest_neighbor[2]):arrow = FancyArrowPatch((x, 0.0), (nearest_neighbor[2], 0.0), color=color[1], **kw)plt.gca().add_patch(arrow)

(图片由作者提供)

因此,最长的提取链是 1 ⇌ 2 ⇌ 3 ⇌ 4 ⇌ 5。请注意,我们看到数据逐渐单调增加,但实际上,漂移的增加或减少可能以任意复杂的方式发生,可以通过时间序列链方法检测到。漂移的关键组成部分是时间序列必须包含具有明确方向性的链。

STUMPY 能够计算:

  1. 锚定的时间序列链(ATSC)-从用户指定的锚(即特定的子序列)开始增长链
  2. 全链集(ALLC)——一组锚定的时间序列链(即每个链以特定的子序列开始),它们不被另一个更长的链所包含
  3. 未锚定的时间序列链—时间序列中无条件最长的链(如果存在长度相同的链,则可能有多个链)

那么,这在真实时间序列中意味着什么呢?让我们来看一个来自 web 查询数据的真实例子!

检索数据

我们将看到一个欠采样且有增长趋势的噪声数据集,这将完美地说明关于时间序列链的想法。该数据包含十年之久的 GoogleTrend 对关键字美国柯尔百货公司(美国零售连锁店)的查询量(从 2004 年到 2014 年每周收集一次)。首先,我们将下载数据,提取数据,并将其插入到 Pandas 数据帧中。

df = pd.read_csv("https://zenodo.org/record/4276348/files/Time_Series_Chains_Kohls_data.csv?download=1")
df.head() volume
0  0.010417
1  0.010417
2  0.010417
3  0.000000
4  0.000000

可视化数据

plt.plot(df['volume'], color='black')
plt.xlim(0, df.shape[0]+12)
color = itertools.cycle(['white', 'gainsboro'])
for i, x in enumerate(range(0, df.shape[0], 52)):plt.text(x+12, 0.9, str(2004+i), color="black", fontsize=20)rect = Rectangle((x, -1), 52, 2.5, facecolor=next(color))plt.gca().add_patch(rect)

(图片由作者提供)

上面的原始时间序列显示了关键字“美国柯尔百货公司”十年的网络查询量,其中每个交替的白色和灰色垂直带代表从 2004 年到 2014 年的 52 周期间。如图所示,该时间序列有一个显著但不令人惊讶的“年末假日高峰”。回到时间序列链,我们可以看到,随着时间的推移,凸起通常会增加,因此我们可能能够在计算非锚定链时捕捉到这一点。

然而,正如我们在上面学到的,为了计算任何时间序列链,我们还需要左和右矩阵轮廓指数。幸运的是,根据 STUMPY 文档,stumpy.stump()函数不仅分别返回 NumPy 数组第一和第二列中的(双向)矩阵轮廓和矩阵轮廓索引,而且第三和第四列分别由左矩阵轮廓索引和右矩阵轮廓索引组成。

计算左和右矩阵轮廓指数

因此,让我们继续计算矩阵轮廓指数,我们将设置窗口大小m = 20,这是一个“凸起”的大致长度。

m = 20
mp = stumpy.stump(df['volume'], m=m)

计算非锚定链

现在,有了左右矩阵轮廓索引,我们准备调用全链集 STUMPY 函数,stumpy.allc(),它不仅返回全链集,而且作为副产品,它还返回无条件最长链,也称为非锚定链。后者才是我们真正感兴趣的。

all_chain_set, unanchored_chain = stumpy.allc(mp[:, 2], mp[:, 3])

可视化未锚定的链

plt.plot(df['volume'], linewidth=1, color='black')
for i in range(unanchored_chain.shape[0]):y = df['volume'].iloc[unanchored_chain[i]:unanchored_chain[i]+m]x = y.index.valuesplt.plot(x, y, linewidth=3)
color = itertools.cycle(['white', 'gainsboro'])
for i, x in enumerate(range(0, df.shape[0], 52)):plt.text(x+12, 0.9, str(2004+i), color="black", fontsize=20)rect = Rectangle((x, -1), 52, 2.5, facecolor=next(color))plt.gca().add_patch(rect)

(图片由作者提供)

plt.axis('off')
for i in range(unanchored_chain.shape[0]):data = df['volume'].iloc[unanchored_chain[i]:unanchored_chain[i]+m].reset_index().valuesx = data[:, 0]y = data[:, 1]plt.axvline(x=x[0]-x.min()+(m+5)*i + 11, alpha=0.3)plt.axvline(x=x[0]-x.min()+(m+5)*i + 15, alpha=0.3, linestyle='-.')plt.plot(x-x.min()+(m+5)*i, y-y.min(), linewidth=3)

(图片由作者提供)

发现的链显示,在十年中,凸起从覆盖感恩节(实线垂直线)和圣诞节(虚线垂直线)之间的平稳凸起过渡到以感恩节为中心的更尖锐的凸起。这似乎反映了“网络星期一”日益增长的重要性,这是感恩节后星期一的营销术语。这个短语是营销公司为了说服消费者网上购物而创造的。这个词在 2005 年 11 月 28 日的一篇题为“网络星期一迅速成为今年最大的网上购物日之一”的新闻稿中首次亮相。请注意,这个日期与我们链中第一次看到锐化峰值的时间一致。

我们似乎还“遗漏”了链条中的几个环节。然而,请注意,数据是有噪声的和欠采样的,并且“错过的”颠簸失真太大,不符合一般的发展趋势。这个嘈杂的例子实际上说明了时间序列链技术的鲁棒性。如前所述,我们实际上并不需要“完美”的数据来寻找有意义的链。即使一些链接被严重扭曲,被发现的链仍然能够包括所有其他进化的模式。

最后一个要考虑的是链在预测或预报未来方面的潜在用途。人们可以利用链条中不断发展的链接来预测下一次碰撞的形状。我们建议读者参考矩阵简介 VII 以了解关于该主题的进一步讨论。

摘要

就是这样!您刚刚学习了如何使用矩阵剖面指数和利用stumpy.allc()函数在数据中识别方向趋势(也称为链)的基础知识。

资源

Matrix Profile VII
Matrix Profile VII 补充资料
STUMPY Matrix Profile 文档
STUMPY Matrix Profile Github 代码库

← 第二部分:STUMPY 基础知识 | 第四部分:语义切分 →

第 4 部分:语义分割

原文:https://towardsdatascience.com/part-4-semantic-segmentation-b42c3792833d?source=collection_archive---------21-----------------------

用 STUMPY 寻找时间序列状态变化

(图片由罗南古田提供)

整体大于部分之和

(图片由作者提供)

STUMPY 是一个强大且可扩展的 Python 库,用于现代时间序列分析,在其核心,有效地计算出一种叫做矩阵轮廓的东西。这个多部分系列的目标是解释什么是 matrix profile,以及如何开始利用 STUMPY 完成所有现代时间序列数据挖掘任务!

注:这些教程最初出现在 STUMPY 文档 中。

第 1 部分:矩阵轮廓图
第 2 部分: STUMPY 基础知识
第 3 部分:时间序列链
第 4 部分:语义分割
第 5 部分:用 STUMPY 快速近似矩阵轮廓图
第 6 部分:用于流式时间序列数据的矩阵轮廓图
第 7 部分:用 STUMPY 快速模式搜索 10: 发现多维时间序列模体
第 11 部分:用户引导的模体搜索
第 12 部分:机器学习的矩阵轮廓

用 FLUSS 和 FLOSS 识别时间序列数据中的变化点

本例利用了从矩阵图 VIII 研究论文中获得的主要信息。对于适当的上下文,我们强烈建议您先阅读本文,但要知道我们的实现是紧密遵循本文的。

根据上述出版物,“一个人可以对[越来越多的时间序列数据被捕获]执行的最基本的分析之一是将其分割成同质区域。”换句话说,如果您能够将长时间序列数据分割或分割成k个区域(其中k较小),并且最终目标是只向人类(或机器)注释者呈现k个简短的代表性模式,以便为整个数据集生成标签,这不是很好吗?这些分割的区域也被称为“政权”。此外,作为一种探索性工具,人们可能会在数据中发现以前未发现的新的可操作的见解。快速低成本单值语义分割(FLUSS)是一种算法,它产生一种称为“弧形曲线”的东西,用有关政权变化可能性的信息来注释原始时间序列。快速低成本在线语义分割(FLOSS)是 FLUSS 的一种变体,根据原始论文,它是域不可知的,提供具有可操作实时干预潜力的流功能,并适用于真实世界数据(即,不假设数据的每个区域都属于定义明确的语义段)。

为了演示 API 和基本原理,我们将观察躺在医疗倾斜台上的健康志愿者的动脉血压(ABP)数据,并观察我们是否能够检测到倾斜台何时从水平位置倾斜到垂直位置。这与原始论文中的数据相同(见上文)。

入门指南

让我们导入加载、分析和绘制数据所需的包。

%matplotlib inlineimport pandas as pd
import numpy as np
import stumpy
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, FancyArrowPatch
from matplotlib import animation
from IPython.display import HTMLplt.rcParams["figure.figsize"] = [20, 6]  # width, height
plt.rcParams['xtick.direction'] = 'out'

检索数据

df = pd.read_csv("https://zenodo.org/record/4276400/files/Semantic_Segmentation_TiltABP.csv?download=1")
df.head()time      abp0  06832.01  16928.02  26968.03  36992.04  46980.0

可视化原始数据

plt.plot(df['time'], df['abp'])
rect = Rectangle((24000,2400),2000,6000,facecolor='lightgrey')
plt.gca().add_patch(rect)

(图片由作者提供)

我们可以清楚地看到,在time=25000附近有一个变化,对应于桌子被直立倾斜的时间。

弗卢斯

不使用完整的数据集,让我们直接放大并分析x=25000前后的 2500 个数据点(参见论文中的图 5)。

start = 25000 - 2500
stop = 25000 + 2500
abp = df.iloc[start:stop, 1]
plt.plot(range(abp.shape[0]), abp)
plt.ylim(2800, 8500)
plt.axvline(x=2373, linestyle="dashed")style="Simple, tail_width=0.5, head_width=6, head_length=8"
kw = dict(arrowstyle=style, color="k")# regime 1
rect = Rectangle((55,2500), 225, 6000, facecolor='lightgrey')
plt.gca().add_patch(rect)
rect = Rectangle((470,2500), 225, 6000, facecolor='lightgrey')
plt.gca().add_patch(rect)
rect = Rectangle((880,2500), 225, 6000, facecolor='lightgrey')
plt.gca().add_patch(rect)
rect = Rectangle((1700,2500), 225, 6000, facecolor='lightgrey')
plt.gca().add_patch(rect)
arrow = FancyArrowPatch((75, 7000), (490, 7000), connectionstyle="arc3, rad=-.5", **kw)
plt.gca().add_patch(arrow)
arrow = FancyArrowPatch((495, 7000), (905, 7000), connectionstyle="arc3, rad=-.5", **kw)
plt.gca().add_patch(arrow)
arrow = FancyArrowPatch((905, 7000), (495, 7000), connectionstyle="arc3, rad=.5", **kw)
plt.gca().add_patch(arrow)
arrow = FancyArrowPatch((1735, 7100), (490, 7100), connectionstyle="arc3, rad=.5", **kw)
plt.gca().add_patch(arrow)# regime 2
rect = Rectangle((2510,2500), 225, 6000, facecolor='moccasin')
plt.gca().add_patch(rect)
rect = Rectangle((2910,2500), 225, 6000, facecolor='moccasin')
plt.gca().add_patch(rect)
rect = Rectangle((3310,2500), 225, 6000, facecolor='moccasin')
plt.gca().add_patch(rect)
arrow = FancyArrowPatch((2540, 7000), (3340, 7000), connectionstyle="arc3, rad=-.5", **kw)
plt.gca().add_patch(arrow)
arrow = FancyArrowPatch((2960, 7000), (2540, 7000), connectionstyle="arc3, rad=.5", **kw)
plt.gca().add_patch(arrow)
arrow = FancyArrowPatch((3340, 7100), (3540, 7100), connectionstyle="arc3, rad=-.5", **kw)
plt.gca().add_patch(arrow)

(图片由作者提供)

粗略地说,在上面的截断图中,我们看到两个区域之间的分割发生在time=2373(垂直虚线)附近,在那里第一个区域(灰色)的模式没有跨越到第二个区域(橙色)(参见原始论文中的图 2)。因此“弧形曲线”是通过沿时间序列滑动并简单地计算其他模式“越过”该特定时间点的次数(即“弧形”)来计算的。从本质上讲,可以通过查看矩阵轮廓指数来提取这些信息(矩阵轮廓指数会告诉您最近的邻居在时间序列上的位置)。因此,我们预计在重复图案彼此靠近的地方电弧数高,在没有交叉电弧的地方电弧数低。

在我们计算“弧形曲线”之前,我们需要首先计算标准矩阵轮廓,我们可以看到窗口大小大约为 210 个数据点(由于主题/领域专家的知识)。

m = 210
mp = stumpy.stump(abp, m=m)

现在,为了计算“弧线”并确定状态变化的位置,我们可以直接调用stumpy.fluss()函数。但是,请注意stumpy.fluss()需要以下输入:

  1. 矩阵轮廓索引mp[:, 1](不是矩阵轮廓距离)
  2. 一个合适的子序列长度,L(为了方便起见,我们只选择它等于窗口大小,m=210)
  3. 要搜索的区域数量n_regimes(本例中为 2 个区域)
  4. 一个排除因子,excl_factor,使弧线的起点和终点无效(根据论文,1-5 之间的任何值都是合理的)
L = 210
cac, regime_locations = stumpy.fluss(mp[:, 1], L=L, n_regimes=2, excl_factor=1)

请注意,stumpy.fluss()实际上返回了一种叫做“校正弧线”(CAC)的东西,它使这样一个事实正常化,即通常在时间序列的开始和结束附近的时间点上跨越的弧线较少,而在时间序列的中间附近跨越的可能性较大。另外,stumpy.fluss()返回虚线的区域或位置。让我们绘制原始时间序列(顶部)以及校正后的弧线(橙色)和单一状态(垂直虚线)。

fig, axs = plt.subplots(2, sharex=True, gridspec_kw={'hspace': 0})
axs[0].plot(range(abp.shape[0]), abp)
axs[0].axvline(x=regime_locations[0], linestyle="dashed")
axs[1].plot(range(cac.shape[0]), cac, color='C1')
axs[1].axvline(x=regime_locations[0], linestyle="dashed")

(图片由作者提供)

在这里,我们看到stumpy.fluss()不仅成功地识别出存在政权更迭,而且能够清晰明确地区分两种政权。

丝棉

与 FLUSS 不同,FLOSS 关注的是流数据,因此它计算的是修正圆弧曲线(CAC)的修改版本,它是严格单向的(CAC_1D ),而不是双向的。也就是说,我们不期望从两个方向交叉的可能性相等,而是期望更多的交叉指向未来(更少的指向过去)。所以,我们可以手动计算CAC_1D

# This is for demo purposes only. Use stumpy.floss() below!
cac_1d = stumpy._cac(mp[:, 3], L, bidirectional=False, excl_factor=1)

并且将CAC_1D(蓝色)与双向CAC(橙色)进行比较,我们看到全局最小值大约在相同的位置(参见原始论文中的图 10)。

fig, axs = plt.subplots(2, sharex=True, gridspec_kw={'hspace': 0})
axs[0].plot(np.arange(abp.shape[0]), abp)
axs[0].axvline(x=regime_locations[0], linestyle="dashed")
axs[1].plot(range(cac.shape[0]), cac, color='C1')
axs[1].axvline(x=regime_locations[0], linestyle="dashed")
axs[1].plot(range(cac_1d.shape[0]), cac_1d)

(图片由作者提供)

使用 FLOSS 传输数据

然而,我们可以直接调用实例化一个流对象的stumpy.floss()函数,而不是像上面那样手工计算CAC_1D。为了演示stumpy.floss()的用法,让我们取一些old_data并像上面那样计算它的矩阵轮廓指数:

old_data = df.iloc[20000:20000+5000, 1].values  # This is well before the regime change has occurredmp = stumpy.stump(old_data, m=m)

现在,我们可以像前面一样计算双向修正弧线,但我们希望看到弧线在添加新数据点后会如何变化。因此,让我们定义一些要流入的新数据:

new_data = df.iloc[25000:25000+5000, 1].values

最后,我们调用stumpy.floss()函数来初始化一个流对象并传入:

  1. old_data生成的矩阵轮廓(仅使用矩阵轮廓索引)
  2. “旧数据”用于生成 1 中的矩阵轮廓。
  3. 矩阵轮廓窗口大小,m=210
  4. 子序列长度,L=210
  5. 排除因素
stream = stumpy.floss(mp, old_data, m=m, L=L, excl_factor=1)

您现在可以通过stream.update(t)功能用新的数据点t更新stream,这将滑动您的窗口一个数据点,它将自动更新:

  1. CAC_1D(通过.cac_1d_属性访问)
  2. 矩阵轮廓(通过.P_属性访问)
  3. 矩阵轮廓指数(通过.I_属性访问)
  4. 用于产生CAC_1D的数据滑动窗口(通过.T_属性访问——这应该与“旧数据”的长度相同)

让我们用new_data不断更新我们的stream,一次更新一个值,并将它们存储在一个列表中(一会儿你就知道为什么了):

windows = []
for i, t in enumerate(new_data):stream.update(t) if i % 100 == 0:windows.append((stream.T_, stream.cac_1d_))

下面,您可以看到一个动画,它是用新数据更新流的结果。作为参考,我们还绘制了CAC_1D(橙色),这是我们从上面为静态数据手动生成的。您将看到,在动画进行到一半时,状态发生了变化,更新后的CAC_1D(蓝色)将与橙色曲线完美对齐。

fig, axs = plt.subplots(2, sharex=True, gridspec_kw={'hspace': 0})axs[0].set_xlim((0, mp.shape[0]))
axs[0].set_ylim((-0.1, max(np.max(old_data), np.max(new_data))))
axs[1].set_xlim((0, mp.shape[0]))
axs[1].set_ylim((-0.1, 1.1))lines = []
for ax in axs:line, = ax.plot([], [], lw=2)lines.append(line)
line, = axs[1].plot([], [], lw=2)
lines.append(line)def init():for line in lines:line.set_data([], [])return linesdef animate(window):data_out, cac_out = windowfor line, data in zip(lines, [data_out, cac_out, cac_1d]):line.set_data(np.arange(data.shape[0]), data)return linesanim = animation.FuncAnimation(fig, animate, init_func=init,frames=windows, interval=100,blit=True)anim_out = anim.to_jshtml()
plt.close()  # Prevents duplicate image from displaying
if os.path.exists("None0000000.png"):os.remove("None0000000.png")  # Delete rogue temp fileHTML(anim_out)

(图片由作者提供)

摘要

就是这样!您刚刚学习了如何使用矩阵剖面指数和利用stumpy.fluss()stumpy.floss()以编程方式识别时间序列数据中的变化段/状态的基础知识。

资源

Matrix Profile VIII
STUMPY Matrix Profile 文档
STUMPY Matrix Profile Github 代码库

← 第 3 部分:时间序列链 | 第 5 部分:带 STUMPY 的快速近似矩阵轮廓 →

第 5 部分:用 STUMPY 快速近似矩阵轮廓

原文:https://towardsdatascience.com/part-5-fast-approximate-matrix-profiles-with-scrump-c6d9c984c560?source=collection_archive---------52-----------------------

在很短的时间内计算出大致精确的矩阵轮廓

(图片由 Djim Loic 提供)

整体大于部分之和

(图片由作者提供)

STUMPY 是一个强大且可扩展的 Python 库,用于现代时间序列分析,在其核心,有效地计算出一种叫做矩阵轮廓的东西。这个多部分系列的目标是解释什么是 matrix profile,以及如何开始利用 STUMPY 完成所有现代时间序列数据挖掘任务!

注:这些教程最初出现在 STUMPY 文档 中。

第一部分:矩阵轮廓
第二部分: STUMPY 基础知识
第三部分:时间序列链
第四部分:语义分割
第五部分:快速近似矩阵轮廓与 STUMPY
第六部分:用于流式时间序列数据的矩阵轮廓
第七部分:快速模式搜索与 STUMPY
第八部分:【T21 10: 发现多维时间序列模体
第十一部分:用户引导的模体搜索
第十二部分:机器学习的矩阵轮廓

利用有限的时间和资源计算矩阵轮廓

在第 1 部分:矩阵分布图中,我们定义了矩阵分布图的含义,讨论了计算大型时间序列的矩阵分布图的复杂性,并且在第 2 部分:STUMPY 基础知识中,我们检查了它为我们提供的一些好处。然而,随着时间序列长度的增加,计算矩阵轮廓的成本可能会挑战你的耐心,甚至你的钱包。

在本文的中,介绍了一种称为“SCRIMP++的新方法,它以增量方式计算矩阵轮廓。当只需要一个近似矩阵轮廓时,该算法使用矩阵轮廓计算的某些属性来大大减少总计算时间,在本教程中,我们将演示这种方法如何满足您的应用。

STUMPY 在stumpy.scrump()函数中为自连接和 AB 连接实现了这种方法,当需要更高分辨率的输出时,它允许矩阵轮廓被容易地细化。

入门指南

首先,让我们导入一些将用于数据加载、分析和绘图的包。

%matplotlib inlineimport pandas as pd
import stumpy
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangleplt.rcParams["figure.figsize"] = [20, 6]  # width, height
plt.rcParams['xtick.direction'] = 'out'

加载 Steamgen 数据集

该数据是使用模糊模型生成的,该模型用于模拟位于伊利诺伊州香槟市的 Abbott 电厂的蒸汽发生器。我们感兴趣的数据特性是输出蒸汽流量遥测,单位为 kg/s,数据每三秒“采样”一次,共有 9600 个数据点。

steam_df = pd.read_csv("https://zenodo.org/record/4273921/files/STUMPY_Basics_steamgen.csv?download=1")
steam_df.head()drum pressure  excess oxygen  water level  steam flow320.08239       2.506774     0.032701    9.3029701321.71099       2.545908     0.284799    9.6626212320.91331       2.360562     0.203652   10.990955 3325.00252       0.027054     0.326187   12.4301074326.65276       0.285649     0.753776   13.681666

可视化 Steamgen 数据集

plt.suptitle('Steamgen Dataset', fontsize='25')
plt.xlabel('Time', fontsize ='20')
plt.ylabel('Steam Flow', fontsize='20')
plt.plot(steam_df['steam flow'].values)

(图片由作者提供)

计算真实矩阵轮廓

现在,作为比较的基准,我们将使用stumpy.stump()函数和m=640的窗口大小来计算完整的矩阵轮廓。

m = 640
mp = stumpy.stump(steam_df['steam flow'], m)
true_P = mp[:, 0]fig, axs = plt.subplots(2, sharex=True, gridspec_kw={'hspace': 0})
plt.suptitle('Motif (Pattern) Discovery', fontsize='25')axs[0].plot(steam_df['steam flow'].values)
axs[0].set_ylabel('Steam Flow', fontsize='20')
rect = Rectangle((643, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
rect = Rectangle((8724, 0), m, 40, facecolor='lightgrey')
axs[0].add_patch(rect)
axs[1].set_xlabel('Time', fontsize ='20')
axs[1].set_ylabel('Matrix Profile', fontsize='20')
axs[1].axvline(x=643, linestyle="dashed")
axs[1].axvline(x=8724, linestyle="dashed")
axs[1].plot(true_P)

(图片由作者提供)

矩阵分布图的全局最小值(虚线)是顶部基序的索引(即,彼此最相似的两个子序列)。当使用矩阵图时,在许多应用中,这是两个最重要的子序列,我们将看到如何使用stumpy.scrump()快速得出一个近似的矩阵图,在很短的时间内挑出这些子序列。

此外,我们将使用下面的帮助器功能直观地比较真实的矩阵轮廓(true_P -用stumpy.stump()计算)和近似的矩阵轮廓(approx_P -用stumpy.scrump()计算)。

def compare_approximation(true_P, approx_P):fig, ax = plt.subplots(gridspec_kw={'hspace': 0}) ax.set_xlabel('Time', fontsize ='20')ax.axvline(x=643, linestyle="dashed")ax.axvline(x=8724, linestyle="dashed")ax.set_ylim((5, 28))ax.plot(approx_P, color='C1', label="Approximate Matrix Profile")ax.plot(true_P, label="True Matrix Profile")ax.legend()

使用 SCRUMP 计算近似矩阵轮廓

为了计算完整的矩阵分布,必须计算整个距离矩阵(即所有子序列对之间的成对距离)。然而,stumpy.scrump()以对角线方式计算这个距离矩阵,但是只使用所有对角线的子集(因此,只使用所有距离的子集)。您想要计算的对角线上的成对距离由percentage参数控制。计算的距离越多,近似值就越好,但这也意味着更高的计算成本。选择值1.0,或所有距离的 100%,产生完全精确的矩阵轮廓(相当于stumpy.stump()的输出)。重要的是要注意,即使正在计算较少的成对距离,也没有近似成对距离。也就是说,你总是保证在percentage <= 1.0approx_P >= true_P,在percentage=1.0approx_P == true_P(即它是精确的)。

现在,让我们调用stumpy.scrump(),通过仅计算所有距离的 1%来近似整个矩阵轮廓(即percentage=0.01):

approx = stumpy.scrump(steam_df['steam flow'], m, percentage=0.01, pre_scrump=False)

有几件事需要注意。首先,我们传入了一个pre_scrump参数,这是stumpy.scrump()的一个预处理步骤,当设置为True时,可以极大地提高近似值。现在,出于演示目的,我们关闭预处理步骤,并在下一节中再次讨论它。其次,stumpy.scrump()初始化并返回一个scrump对象,而不是直接返回矩阵配置文件,我们将在下面看到这为什么有用。

为了检索第一次近似(即,从所有距离的 1%计算的矩阵轮廓),我们简单地调用.update()方法:

approx.update()

我们可以分别通过.P_.I_属性访问更新的矩阵配置文件和矩阵配置文件索引:

approx_P = approx.P_

请记住,近似矩阵轮廓是通过随机计算对角线子集的距离来计算的。所以,每次你通过调用stumpy.scrump()初始化一个新的scrump对象,这将随机打乱距离计算的顺序,这不可避免地导致不同的近似矩阵轮廓(除了当percentage=1.0)。根据您的使用情况,为了确保可重复的结果,您可以考虑在调用stumpy.scrump()之前设置随机种子:

seed = np.random.randint(100000)
np.random.seed(seed)
approx = stumpy.scrump(steam_df['steam flow'], m, percentage=0.01, pre_scrump=**False**)

接下来,让我们在true_P上绘制approx_P,看看它们比较起来有多好:

compare_approximation(true_P, approx_P)

我们可以看到,这种近似(橙色)远非完美,但两者之间有一些相似之处。然而,近似值中的最低点(橙色)并不对应于真正的最小值(蓝色)。

细化矩阵轮廓

然而,我们可以通过再调用.update()九次(即10 * 0.01 = 0.10)来逐步细化近似,因此我们新的近似矩阵轮廓将使用全距离矩阵中所有成对距离的大约 10%来计算。

for _ in range(9):approx.update()approx_P = approx.P_compare_approximation(true_P, approx_P)

(图片由作者提供)

现在,这个结果更有说服力了,它只需要计算所有成对距离的 10%!我们可以看到这两个轮廓非常相似,特别是像全局最小值这样的重要特征几乎处于相同的位置,如果不是相同的话。对于大多数应用来说,这就足够了,因为几个点的偏移通常并不重要,并且必须计算的距离数量减少了十分之一!事实上,我们可以做得更好!

预处理的力量

到目前为止,我们只运行了stumpy.scrump()而没有强大的pre crimp预处理步骤。 PRESCRIMP 是对复杂度为O(n log(n) / s)的时间序列数据进行预处理的算法,其中n是数据点的个数,s称为采样率。stumpy.stump()stumpy.scrump()(没有预裁剪)都是O(n^2)复杂度,所以一般来说,预处理是‘廉价’的。 PRESCRIMP 已经计算了一些成对距离的距离,并且采样率控制了要计算的数量。通常,一个好的值是s=m/4,与典型的禁区大小相同,如果将None传递给scrimp.scrump()函数调用,就会使用这个值。

下面我们将再次用所有对角线的 1%来近似矩阵轮廓,但是这一次,我们将通过设置pre_scrimp=True来启用预处理。显然,这将需要更长的计算时间,因为还需要执行一些计算:

approx = stumpy.scrump(steam_df['steam flow'], m, percentage=0.01, pre_scrump=True, s=None)
approx.update()
approx_P = approx.P_compare_approximation(true_P, approx_P)

然而,人们可以看到,在这个例子中,预处理之后的仅计算 1%的成对距离(即,仅调用.update()一次),近似矩阵轮廓和真实矩阵轮廓在视觉上几乎无法区分。随着时间序列长度的增加,使用预处理的好处会进一步增加。当然,根据您需要分析的时间序列数据的大小以及您可以使用的计算资源,计算更高百分比的距离以确保近似值收敛可能是值得的。

摘要

就是这样!您已经学习了如何使用stumpy.scrump()来近似矩阵轮廓,希望能够在您的应用中使用近似矩阵轮廓。

资源

Matrix Profile Xi
STUMPY Matrix Profile 文档
STUMPY Matrix Profile Github 代码库

← 第 4 部分:语义分割 | 第 6 部分:流式时间序列数据的矩阵轮廓 →

第 7 部分:用 STUMPY 进行快速模式搜索

原文:https://towardsdatascience.com/part-7-fast-pattern-searching-with-stumpy-2baf610a8de1?source=collection_archive---------21-----------------------

为已知模式寻找相似的子序列匹配

(图片由史蒂夫·赖特提供)

整体大于部分之和

(图片由作者提供)

STUMPY 是一个强大且可扩展的 Python 库,用于现代时间序列分析,在其核心,有效地计算出一种叫做矩阵轮廓的东西。这个多部分系列的目标是解释什么是 matrix profile,以及如何开始利用 STUMPY 完成所有现代时间序列数据挖掘任务!

注:这些教程最初出现在 STUMPY 文档 中。

第 1 部分:矩阵轮廓图
第 2 部分: STUMPY 基础知识
第 3 部分:时间序列链
第 4 部分:语义分割
第 5 部分:用 STUMPY 快速近似矩阵轮廓图
第 6 部分:用于流式时间序列数据的矩阵轮廓图
第 7 部分:用 STUMPY 快速模式搜索 10: 发现多维时间序列模体
第 11 部分:用户引导的模体搜索
第 12 部分:机器学习的矩阵轮廓

超越矩阵轮廓

在 STUMPY 的核心,人们可以获取任何时间序列数据,并有效地计算所谓的矩阵轮廓,它基本上以固定的窗口大小m扫描整个时间序列,并为时间序列中的每个子序列找到最接近的邻居。矩阵配置文件允许您确定数据中是否有任何保守行为(即,保守子序列/模式),如果有,它可以告诉您它们在时间序列中的确切位置。在之前的教程中,我们演示了如何使用 STUMPY 轻松获得矩阵轮廓,学习了如何解释结果,以及发现有意义的主题和不一致。虽然当您不知道正在寻找什么模式或保守行为时,这种强力方法可能非常有用,但是对于足够大的数据集,执行这种彻底的成对搜索可能会变得非常昂贵。

然而,如果你已经有一个特定的用户定义的模式,那么你实际上不需要计算完整的矩阵配置文件!例如,您可能已经根据历史股票市场数据确定了一个有趣的交易策略,并且您希望了解过去是否在一个或多个股票代码中观察到了该特定模式。在这种情况下,搜索一个已知的模式或“查询”实际上非常简单,可以通过使用 STUMPY 中出色的core.mass函数快速完成。

在这个简短的教程中,我们将采用一个简单的感兴趣的已知模式(例如,一个查询子序列),我们将在一个单独的独立时间序列中搜索这个模式。我们开始吧!

入门指南

让我们导入加载、分析和绘制数据所需的包

%matplotlib inlineimport pandas as pd
import stumpy
import numpy as np
import numpy.testing as npt
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangleplt.rcParams["figure.figsize"] = [20, 6]  # width, height
plt.rcParams['xtick.direction'] = 'out'

加载索尼 AIBO 机器狗数据集

时间序列数据(下图),T_df,有n = 13000个数据点,它是从索尼爱宝机器狗内部的加速度计收集的,当机器狗从水泥地面走到铺有地毯的地面,最后回到水泥地面时,它跟踪机器狗:

T_df = pd.read_csv("https://zenodo.org/record/4276393/files/Fast_Pattern_Searching_robot_dog.csv?download=1")
T_df.head() Acceleration
0  0.89969
1  0.89969
2  0.89969
3  0.89969
4  0.89969

可视化索尼 AIBO 机器狗数据集

plt.suptitle('Sony AIBO Robot Dog Dataset, T_df', fontsize='30')
plt.xlabel('Time', fontsize ='20')
plt.ylabel('Acceleration', fontsize='20')
plt.plot(T_df)
plt.text(2000, 4.5, 'Cement', color="black", fontsize=20)
plt.text(10000, 4.5, 'Cement', color="black", fontsize=20)
ax = plt.gca()
rect = Rectangle((5000, -4), 3000, 10, facecolor='lightgrey')
ax.add_patch(rect)
plt.text(6000, 4.5, 'Carpet', color="black", fontsize=20)
plt.show()

(图片由作者提供)

在上面的图中,机器狗在水泥地上行走的时间用白色背景显示,而机器狗在地毯上行走的时间用灰色背景突出显示。你注意到在不同的路面上行走有什么明显的不同吗?有什么有趣的见解可以用人眼观察到?在这个时间序列中是否存在任何保守的模式,如果存在,它们在哪里?

你见过这个图案吗?

我们有兴趣在时间序列(上图)中搜索的子序列模式或查询(下图)如下所示:

Q_df = pd.read_csv("https://zenodo.org/record/4276880/files/carpet_query.csv?download=1")plt.suptitle('Pattern or Query Subsequence, Q_df', fontsize='30')
plt.xlabel('Time', fontsize ='20')
plt.ylabel('Acceleration', fontsize='20')
plt.plot(Q_df, lw=2, color="C1")  # Walking on cement
plt.show()

(图片由作者提供)

这个图案Q_df的窗口长度为m = 100,它取自一个完全独立的行走样本。是不是一点都不眼熟?类似的模式是否存在于我们更早的时间序列中,T_df?您能说出收集这个查询样本时机器狗正在哪个表面上行走吗?

要回答其中的一些问题,您可以通过计算一种称为“距离剖面”的东西,将这个特定的查询子序列或模式与完整的时间序列进行比较。本质上,您获取这个查询,Q_df,并通过计算所有可能的(z-归一化欧几里得)成对距离,将其与T_df中的每个子序列进行比较。因此,距离轮廓只是一个一维向量,它告诉你Q_dfT_df中的每个子序列(长度相同)有多相似/不相似。现在,计算距离轮廓的简单算法需要花费O(n*m)时间来处理,但幸运的是,我们可以做得比这好得多,因为存在一种称为“Mueen 的相似性搜索算法” (MASS)的超级有效的方法,它能够以快得多的O(n*log(n))时间(log基数 2)来计算距离轮廓。现在,如果您只有几个短时间序列要分析,这可能不是什么大问题,但是如果您需要用不同的查询子序列多次重复这个过程,那么事情会很快增加。事实上,随着时间序列的长度n和/或查询子序列的长度m变得越来越长,朴素算法将花费太多时间!

用质量计算距离剖面

因此,给定一个查询子序列Q_df和一个时间序列T_df,我们可以执行一个快速相似性搜索,并使用 STUMPY 中的core.mass函数计算距离分布图:

distance_profile = stumpy.core.mass(Q_df["Acceleration"], T_df["Acceleration"])

并且,由于distance_profile包含了Q_dfT_df内每个子序列之间的成对距离的完整列表,我们可以通过找到distance_profile中的最小距离值并提取其位置索引来从T_df中检索最相似的子序列:

idx = np.argmin(distance_profile)print(f"The nearest neighbor to `Q_df` is located at index {idx} in `T_df`")zThe nearest neighbor to `Q_df` is located at index 7479 in `T_df`

所以,为了回答我们之前的问题“在我们之前的时间序列中是否存在类似的模式,T_df?”,让我们继续在T_df中绘制最相似的子序列,它位于索引 7479(蓝色),并用我们的查询模式Q_df(橙色)覆盖它:

# Since MASS computes z-normalized Euclidean distances, we should z-normalize our subsequences before plotting
Q_z_norm = stumpy.core.z_norm(Q_df.values)
T_z_norm = stumpy.core.z_norm(T_df.values[idx:idx+len(Q_df)])plt.suptitle('Comparing The Query (Orange) And Its Nearest Neighbor (Blue)', fontsize='30')
plt.xlabel('Time', fontsize ='20')
plt.ylabel('Acceleration', fontsize='20')
plt.plot(Q_z_norm, lw=2, color="C1")
plt.plot(T_z_norm, lw=2)
plt.show()

(图片由作者提供)

注意,即使查询子序列不完全匹配它的最近邻,STUMPY 仍然能够找到它!然后,为了回答第二个问题“你能说出当这个查询样本被收集时机器狗正在哪个表面上行走吗?”,我们可以精确地看到idxT_df中的位置:

plt.suptitle('Sony AIBO Robot Dog Dataset, T_df', fontsize='30')
plt.xlabel('Time', fontsize ='20')
plt.ylabel('Acceleration', fontsize='20')
plt.plot(T_df)
plt.text(2000, 4.5, 'Cement', color="black", fontsize=20)
plt.text(10000, 4.5, 'Cement', color="black", fontsize=20)
ax = plt.gca()
rect = Rectangle((5000, -4), 3000, 10, facecolor='lightgrey')
ax.add_patch(rect)
plt.text(6000, 4.5, 'Carpet', color="black", fontsize=20)
plt.plot(range(idx, idx+len(Q_df)), T_df.values[idx:idx+len(Q_df)], lw=2)
plt.show()

(图片由作者提供)

正如我们在上面看到的,与Q_df最近的邻居(橙色)是机器狗在地毯上行走时发现的子序列,事实证明,Q_df是从机器狗也在地毯上行走的独立样本中收集的!为了更进一步,我们可以查看顶部k = 16最近邻居的位置,而不是提取唯一的顶部最近邻居:

# This simply returns the (sorted) positional indices of the top 16 smallest distances found in the distance_profile
k = 16
idxs = np.argpartition(distance_profile, k)[:k]
idxs = idxs[np.argsort(distance_profile[idxs])]

然后让我们根据它们的索引位置来绘制所有这些子序列:

plt.suptitle('Sony AIBO Robot Dog Dataset, T_df', fontsize='30')
plt.xlabel('Time', fontsize ='20')
plt.ylabel('Acceleration', fontsize='20')
plt.plot(T_df)
plt.text(2000, 4.5, 'Cement', color="black", fontsize=20)
plt.text(10000, 4.5, 'Cement', color="black", fontsize=20)
ax = plt.gca()
rect = Rectangle((5000, -4), 3000, 10, facecolor='lightgrey')
ax.add_patch(rect)
plt.text(6000, 4.5, 'Carpet', color="black", fontsize=20)for idx in idxs:plt.plot(range(idx, idx+len(Q_df)), T_df.values[idx:idx+len(Q_df)], lw=2)
plt.show()

(图片由作者提供)

不出所料,当机器狗在地毯(灰色)上行走时,可以找到与Q_df最近的前k = 16(或最佳匹配,如上多种颜色所示)!

摘要

就是这样!您现在已经获得了一个感兴趣的已知模式(或查询),使用 STUMPY 在core.mass中运行它,并且您能够在另一个时间序列中快速搜索这个模式。有了这些新发现的知识,你现在可以在你自己的时间序列项目中寻找模式。编码快乐!

附加注释-具有非归一化欧几里得距离的距离剖面

有时,您可能希望使用非归一化的欧几里德距离作为相似性/不相似性的度量,因此,您可以使用core.mass_absolute函数,而不是使用core.mass(在计算成对欧几里德距离之前,首先对您的子序列进行 z 归一化)。这是为那些对计算互补的stumpy.aampstumpy.aampedstumpy.gpu_aampstumpy.ammpi函数中可用的非归一化矩阵轮廓感兴趣的人提供的。

奖金部分——是什么让质量如此之快?

MASS 比简单方法快得多的原因是因为 MASS 使用快速傅立叶变换(FFT)将数据转换到频域,并执行所谓的“卷积”,这将m操作减少到log(n)操作。你可以在最初的 Matrix Profile I 论文中了解更多信息。

下面是计算距离剖面的一个简单实现:

def compute_naive_distance_profile(Q, T):Q = Q.copy()T = T.copy()n = len(T)m = len(Q)naive_distance_profile = np.empty(n - m + 1) start = time.time()Q = stumpy.core.z_norm(Q)for i in range(n - m + 1):naive_distance_profile[i] = np.linalg.norm(Q - stumpy.core.z_norm(T[i:i+m]))naive_elapsed_time = time.time()-start print(f"For n = {n} and m = {m}, the naive algorithm takes {np.round(naive_elapsed_time, 2)}s to compute the distance profile") return naive_distance_profile

对于随机时间序列T_random,有一百万个数据点和一个随机查询子序列Q_random:

Q_random = np.random.rand(100)
T_random = np.random.rand(1_000_000)naive_distance_profile = compute_naive_distance_profile(Q_random, T_random)For n = 1000000 and m = 100, the naive algorithm takes 44.1s to compute the distance profile

朴素算法需要半分多钟来计算!然而,MASS 可以在大约 1 秒钟内处理这个(甚至更大的数据集):

start = time.time()
mass_distance_profile = stumpy.core.mass(Q_random, T_random)
mass_elapsed_time = time.time()-startprint(f"For n = {len(T_random)} and m = {len(Q_random)}, the MASS algorithm takes {np.round(mass_elapsed_time, 2)}s to compute the distance profile")For n = 1000000 and m = 100, the MASS algorithm takes 1.13s to compute the distance profile

为了绝对确定,让我们确保并检查两种方法的输出是否相同:

npt.assert_almost_equal(naive_distance_profile, mass_distance_profile)

成功,没有错误!这意味着两个输出是相同的。来吧,试一试!

资源

欧氏距离下时间序列子序列的最快相似性搜索算法
STUMPY 矩阵概要文档
STUMPY 矩阵概要 Github 代码库

← 第 6 部分:流式时间序列数据的矩阵剖面图 | 第 8 部分:AB-Joins with STUMPY →

第二部分:孟加拉语。人工智能手写字素分类模型增强

原文:https://towardsdatascience.com/part-ii-bengali-ai-handwritten-grapheme-classification-model-enhancements-20961b0805f?source=collection_archive---------55-----------------------

探索 CNN 图像分类模型的改进

工作主持人: 大卫·柯布迪杰森·卡茨迈克尔·哈德奈娜·沃顿**

查看 系列第一部分 第三部分

更新型号笔记本

转移模型笔记本

跟进我们的第一篇文章,其中我们概述了我们的基线模型;制作这篇文章是为了进一步记录我们团队在孟加拉卡格尔比赛中的努力。AI 手写字形分类大赛。总之,我们的目标是使用卷积神经网络(CNN)对手写孟加拉字符的图像进行分类。我们在这个过程中的最初步骤已经在上面链接的最初文章中介绍过了。在这里,我们记录了我们采取的额外步骤,如数据扩充、迁移学习、ResNet 和超参数调整,以改进我们的基线模型。

正如我们在上一篇文章中提到的,我们希望使用数据增强来扩展我们的训练数据集,并创建一个更强大的模型。数据扩充是通过操纵现有图像的空间方向和大小来改变训练集中的现有图像从而生成新图像的过程。潜在的想法是,这些改变的图像可能类似于现实生活和测试数据集中可能出现的变化。对于手写的孟加拉字符,很明显,对于给定的字素词根、发音元音和发音辅音会有轻微的变化。因此,我们希望用增强图像训练模型将防止过度拟合,并正确地分类字符的轻微变化。

出于我们的目的,我们应用了三种不同的数据增强技术。我们使用的函数来自 Keras 中的 ImageDataGenerator 类,它清晰地输出与输入维数相同的图像。我们首先在 Keras 中实现了旋转功能,旋转范围为 5 度。这将产生新生成的训练图像,这些图像将在-5 度和+5 度之间随机旋转(见图 1)。

图 1

另外,我们上下左右移动了图像。这是由 Keras 类 ImageDataGenerator 中的宽度和高度移动参数 width_shift_rangeheight_shift_range 实现的。 width_shift_range 函数将随机将图像向左或向右移动图像总宽度的一定百分比。高度功能以类似的方式运行(见图 2)。

图 2

最后,我们应用了随机缩放论证。这个函数随机放大和缩小图像(见图 3)。由于数据的性质(即人们不写翻转的字母),我们没有实现垂直翻转、水平翻转和反射参数。我们用来训练卷积神经网络(CNN)的图像是灰度的;因此,操纵颜色通道也是无益的。

图 3

尽管我们做出了努力,我们使用的数据扩充程序并没有显著改善我们的模型。这可能与用于训练模型的图像已经有相当多的变化这一事实有关,因为它们已经是手写图像(天生就有变化)。换句话说,训练集已经具有这些增强技术将模拟的变化。

下一个改进我们模型的尝试是通过迁移学习。我们首先调查了 Keras 网页上记录的一个玩具例子。示例模型的任务是在流行的 MNIST 数据集中对手写数字从 0 到 9 进行分类。迁移学习的玩具例子是通过在 MNIST 数据集的前五个数字(0-4)上训练 CNN 来执行的。接下来,冻结卷积层,添加然后调整密集层,以对最后五位数字(5–9)进行分类。使用这种方法,在第一个五位分类器上五个时期之后,CNN 具有 99.8%的测试准确度,并且在对原始分类器进行调整和实施迁移学习之后,对于最终的五位分类器具有 99.2%的测试准确度。我们的团队复制了这种方法,并在一个类别子集上训练了一个神经网络,然后使用这些训练好的权重来分类下一个类别子集。我们发现这种方法收效甚微。这种方法可能受益于额外的时间,然而,该技术在 MNIST 数据集上的成功是有意义的,因为神经网络只需分类 10 个类。相比之下,当组合所有的字素词根、元音发音符号和辅音发音符号时,我们的数据集总共有 186 个类。

我们下一次迁移学习的尝试源于我们在关于这个项目的上一篇文章的“后续步骤”部分提到的一篇论文。我们发现了 2019 年 2 月发表的一篇有趣的论文,该论文使用迁移学习来构建深度 NN。我们试图通过迁移学习来利用他们在 GitHub 存储库中公开发布的权重和代码。已发表的模型在“BanglaLekha-Isolated 数据集”(Chatterjee et al .,2019)上经过 47 个历元后,准确率达到 96.12%。不幸的是,在尝试利用该模型的权重进行迁移学习时,我们在配置过程中遇到了错误,这使我们无法继续沿着这条道路前进。

最后,我们尝试使用 Keras 的内置图像分类器进行迁移学习,该分类器已经在一个名为 ImageNet 的大型图像库中进行了训练。ImageNet 分类器权重在彩色(RGB)图像上训练。为了利用分类器,我们首先成功地将灰度图像转换为 RGB 图像。然而,当我们在 CNN 上添加新的可调密集层时,我们的计算能力最终限制了我们使用冻结的 ImageNet 权重。我们遇到了许多内存过载错误。为了解决这个问题,如果有必要的资金,我们可以尝试使用谷歌云计算来完成这项任务。

**在尝试了迁移学习和数据扩充之后,我们试图实现一个模仿 ResNet 结构的 CNN。ResNet 是一个“剩余学习框架,它简化了比以前使用的网络更深入的网络训练,”正如建模技术的创造者,康奈尔大学的计算机科学家所说。当何等人在 2015 年发表“图像识别深度残差学习”时,人们普遍认为卷积神经网络的深度对模型的预测能力有很大影响。要了解原因,我们需要回到 1958 年和 1959 年。在那些年里,神经生理学家大卫·H·哈贝尔和托尔斯滕·威塞尔对猴子和猫进行了研究,以理解和充实视觉机制。他们发现“视觉皮层中的许多神经元有一个小的局部感受野,这意味着它们只对位于视野有限区域的视觉刺激做出反应。”

图 4(https://www . research gate . net/figure/Natural-scenes-and-curvature-detection-a-photo-of-Torsten-Wiesel-and-David-Hubel _ fig 1 _ 311479268)

简而言之,研究人员意识到,每个神经元都部分处理图片,只专注于入射光子平面上的特定区域。科学家们还意识到图像是分等级处理的;这意味着每一级神经元关注图像的不同复杂程度,模型越深入,复杂性就越大。结果,当较低层次识别垂直线时,第二层检测线条图案,第三层识别完整的彩虹等等。每个人都认为,以同样的方式通过卷积网络传递的信息会无限地变得更加复杂,从而更加准确地分类。何等人证明了这一观点是不正确的(见图 5)。

图 5(https://arxiv.org/abs/1512.03385)

研究人员举例说明,随着模型深度的增加,模型的性能会突然快速下降。他们假设消失梯度问题是网络训练时权重剩余减少的结果,导致性能下降。尽管这不是何等人提出的解决方案所要解决的主要问题,但由于消失梯度对非线性 ReLU 函数来说并不是一个大的威胁,所以它还是值得一提的。

**创建残差网络是为了简化模型训练;"当你初始化一个正则网络时,它的权值接近于零,所以网络只是输出接近于零的值。如果添加跳过连接,生成的网络仅输出其输入的副本;换句话说,它最初为身份功能建模。如果目标函数相当接近身份函数(这是经常发生的情况),这将大大加快训练速度。当何等人的开创性论文发表时,这一想法是革命性的,因为它允许信号轻松地穿过网络。ResNet 也可以解释为一堆 ru,每个残差单元就像一个小型神经网络(每个快捷连接覆盖一个完整的网络)。

我们使用 ResNet 快捷方式进行连接,使我们的模型更加高效和有效的训练。然而,与我们的预期相反,该模型在准确性和损失方面表现差 5%至 10%,准确性低于我们以前的任何尝试。

图 6(https://machine learning mastery . com/how-to-implementing-major-architecture-innovations-for-卷积神经网络/ )

我们假设孟加拉字母识别的身份和目标功能不相似,因为我们试图在同一张图片上使用 3 种不同的模型对 3 种不同的特征进行分类。因此,没有单一的标识函数可以映射单一的字形。

超参数调整对于训练是必不可少的,因为改进神经网络很大程度上是由于启发式。测试特定参数的不同组合可以显著提高模型的整体性能。我们调整了以下超参数:步幅、填充、卷积层数、滤波器数量和卷积的内核大小。

跨距是对图像中像素区域之间重叠程度的度量。步幅越大,丢失的信息就越多。填充是指用零值框住图像的边缘,以捕捉图像中的所有像素值。如果不对图像进行填充,图像边缘的像素值会丢失,从而导致潜在的大量信息丢失。过滤器是卷积层的组件,它们被训练来识别某种模式,如图像中的对角线。当过滤器“看到”图案时,它们被激活并触发。

虽然填充和步幅的调整对验证准确性没有影响,但卷积层数和内核大小的调整有影响。原始模型有 5 个卷积层,核大小为[7,3,3,3,3],滤波器维数为[64,128,128,256,256]。在对这两个参数进行调整之后,更新的模型具有 7 层,核大小为[5,3,3,3,3,3],滤波器维数为[32,64,64,128,128,256,256]。

通过调整不同的超参数,并将总的历元数增加到 10,我们提高了模型三个不同部分的精度值。

与我们的原始模型类似,字形根分类任务对于训练集具有最低的准确度分数 0.7973,对于验证集具有最低的准确度分数 0.7718(参见图 7)。虽然这些值仍然与辅音和元音音调符号分类的值一样高,但是当我们考虑到该模型需要正确地分类 168 个手写字素词根时,准确度分数是相当显著的。此外,我们原始模型的验证精度为 0.6963,因此我们能够将总体精度提高 10.8%。

图 8 是元音发音符号的训练和验证准确度分数的曲线图。CNN 的元音发音成分的训练精度为 0.9496,验证精度为 0.9277,略高于原始验证精度 0.9185。

辅音发音符号组件的训练精度为 0.9557。验证准确度为 0.9373(见图 9)。这比我们的基线模型验证精度 0.9209 有所提高。

虽然我们的团队对这些结果感到满意,这是对我们基线模型的改进,但我们的目标是通过利用谷歌云计算取得进一步进展。GCP 将为进一步的调整、更深的网络提供额外的计算能力,并有可能让我们克服在尝试使用迁移学习时遇到的内存过载问题。

图 7

图 8

图 9

资源:

**数据增强:https://machine learning mastery . com/how-to-configure-image-Data-Augmentation-when-training-deep-learning-neural-networks/,https://keras.io/preprocessing/image/,https://towards Data science . com/exploring-image-Data-Augmentation-with-keras-and-tensor flow-a 8162d 89 b 844

**转学:【https://keras.io/examples/mnist_transfer_cnn/】T2,【https://arxiv.org/html/1902.11133】T4,https://github.com/swagato-c/bangla-hwcr-present

**ResNet:https://www . researchgate . net/figure/Natural-scenes-and-curvature-detection-a-photo-of-Torsten-Wiesel-and-David-Hubel _ fig 1 _ 311479268,https://machinelingmastery . com/how-to-implementation-major-architecture-innovations-for-convolutionary-neural-networks/,https://arxiv.org/abs/1512.03385,

**正文引用:第。471 Ch。14:使用 CNN 的深度计算机视觉;盖伦,奥雷连恩。"使用 Scikit-Learn、Keras 和 TensorFlow 进行机器实践学习,第二版."奥赖利在线学习,奥赖利媒体公司。

第二部分:利用人工智能打击假新闻

原文:https://towardsdatascience.com/part-ii-using-a-i-to-combat-fake-news-modeling-update-d6931ff0f519?source=collection_archive---------64-----------------------

基于竞赛获胜模式

所进行的工作: 大卫·柯布迪杰森·卡茨迈克尔·哈德奈娜·沃顿**

第一部分:利用人工智能打击假新闻

第三部:利用人工智能打击假新闻最终模式

在这篇关于假新闻分类的后续文章中,我们将介绍我们自己的更新模型,并带您了解相关步骤。简而言之,手头的任务由 49,972 个观测值组成。在这 49,972 人中,约有 75%或 36,545 人属于“无关”阶层。任务的目标是将输入数据分类为(1)同意,(2)不同意,(3)讨论或(4)不相关,输入数据是文章的标题及其相关的文章正文。讨论标签妥协了 17.8% (8,8,909 obs。)的数据,其次是同意标签(7.3%)和不同意标签(1.68%)。

图 1 —站姿计数的条形图。这是一个不平衡的数据集。

竞赛网站为参赛选手提供训练集和测试集,以及加权准确率达到 79.53%的基线 GradientBoosting 分类器。任务是一个多标签多类问题,其中网络需要首先决定标题和正文是相关还是不相关,然后,如果两者相关,则将它们的关系归类为同意不同意讨论

参赛作品的准确性分数通过比赛组织者给出的函数计算得出,可总结为:

图 2 —竞赛的评分结构

获奖模型

获胜的模型具有 82.02%的准确率,是我们在这个项目中试图改进的模型。获胜模型的神经网络体系结构如下:

图 3 —竞争获胜的 CNN 模型结构(https://github . com/Cisco-Talos/fnc-1/tree/master/deep _ learning _ model)

该模型的架构将问题视为多类别、多标签问题,并将输入(标题文本和正文)输入网络。然而,在这样做的时候,它们使用不同的嵌入层,为标题和/或正文定制,随后在网络中连接输入。输入通过一系列相同的卷积层,最终通过一系列级联后的密集层。网络的最后一层是具有 4 个张量的密集层,代表 2 个类别及其 3 个(同意、不同意、讨论)和 1 个标签(相关、不相关)。

然而,该模型不在神经网络中处理工程特征,例如关于文本的情感特征。相反,模型的架构师选择使用 XGBoost 分类器对数据进行分类。

图 4 —竞赛获奖 XGBoost 模型结构(【https://github.com/Cisco-Talos/fnc-1/tree/master/tree_model】T2)

然后,他们将 CNN 和 XGBoost 这两个模型结合起来,用加权平均进行预测。用这种技术,它们达到 82.02%。

我们的模型

我们的模型改进了两个要点:(1)将问题视为分类问题,以及(2)将工程特征输入 CNN。

将问题重新定义为分类

竞赛定义的问题,如上所述,本质上是一个多标签多类问题。然而,我们不必作为一个整体来解决它。我们可以将问题分成两个主要部分,在这里我们为两种不同的分类训练模型。

第一个模型是对标题和正文是否相关进行分类。这个模型包括标题、正文、工程特征和标签。但需要注意的是,竞赛给出的数据并没有任何名为“相关”的标签。相反,如果相关,数据简单地将标题/正文关系分类为同意/不同意/讨论。因此,我们需要创建一个新的数据集,用标签“相关”代替“同意/不同意/讨论”。为此,我们只需使用以下代码块:

图 5 —数据预处理代码

我们将 agree 数据集(指仅具有“相关”标题/正文对的数据集)与仅具有“不相关”标签的相关数据集连接起来。然后,我们简单地对标签中不是“无关”和“相关”的任何内容进行编码。这也允许我们使用整个数据集来训练相关/不相关的模型。重要的是要记住在拼接后对新数据帧进行洗牌。如果没有它,数据集标签将在开始和结束时被极化。(上方无关,下方相关)。

图 6 —数据采样代码

第二个模型简单地将标题和正文的关系分为同意/不同意/讨论。第二个模型的数据集明显小于第一个模型的数据集。这是因为整个数据中只有 25%实际上被归类为“相关”。还需要注意的是,这两个模型是相同的。

模型架构

图 7 —具有三个输入的初始模型架构。一个是标题的卷积层,一个是正文的卷积层,一个是工程特征的密集层。

我们没有使用 XGBoost,而是决定为网络创建第三个输入,由密集层组成。该输入将是矩阵 nx3,其中 n 是观察的数量,3 表示三个工程特征:[“fk _ scores”、“word_count”、“num _ grammar _ errors”]。所有这三个特征都是针对身体的。fk_score 是一个广泛使用的语言指标,用来衡量文章所用语言的复杂程度。Flesch-Kincaid 等级测试是一种可读性测试,旨在表明一篇英语文章的理解难度。其计算方法如下:

图 8——flesch-Kincaid 等级水平公式

该函数的结果是一个与美国年级相对应的数字。“num_grammar_errors”是使用一个名为语言工具的程序计算出来的,该工具可以检查文本中的语法错误。该模型由两个嵌入不同的细胞神经网络和一个密集网络组成。这三个层随后会聚并连接,在预测之前被处理另外几个密集层。

卷积层

图 CNN 的代码

卷积网络(模型的输入 1 和输入 2)遵循具有两个卷积层的简单架构。它们输出具有 34 个张量的密集层,然后连接到连接层。

嵌入层作为网络的第一层,使用之前使用 Google 的 word2vec 计算的嵌入权重进行初始化。

在我们训练嵌入权重之前,我们通过去掉标点符号,然后将文本标记为单词数组来处理输入数据。我们考虑过使用一种语言词根简化方法,将单词转换成它们的词根。使得“描述”、“描述【T3”),都变成了“描述”。然而,由于嵌入问题,我们决定在这个版本的模型中不使用根。

图 10 —创建训练数据的代码

图 11 —寻根代码

然后我们导入 Google 已经在数十亿篇新闻文章上训练过的 word2vec:

图 12 —导入 word2vec 的代码

然后,在单个嵌入矩阵创建方法中,我们为一致数据集和相关数据集分别传入模型的标题和主体。这为我们提供了 4 个矩阵,用于两种分类的 2 个不同模型。

图 13 —数据嵌入代码

致密层

网络的密集层也非常简单。我们使用了以下架构:

图 14 —创建 MLP 的代码

需要注意的是,虽然我们没有为它编写代码;我们使用 LabelEncoding 和 StandardScaler 对工程特征和标签进行预处理。在标签编码之后,我们对多标签同意/不同意/讨论模型使用了一次热编码。

结果

计算竞争分数所描述的加权准确度分数,其中分数的四分之一对应于正确地将标题-正文对分类为相关或不相关,分数的剩余部分对应于正确地将标题-正文对表征为同意、不同意或正文讨论标题的准确度分数。从下面的图表中我们可以看到,将标题-正文对分类为相关或不相关的准确率为 73.13%。

图 15 —测试准确率为 73.12%的训练结果

令人惊讶的是,在这 8 个时期中,训练和测试分数保持不变。下图显示了第二个 CNN 的准确性得分,它将标题-正文对分为同意、不同意或讨论类别。如前所述,只有大约 25%的数据被输入到第二 CNN 中,因为其他 75%在第一 CNN 中被分类为不相关。在 4 个时期之后,训练准确度分数为 96.01%,并且测试准确度分数为 94.97%。整体加权准确率得分为 89.51% = 73.13( ) + 94.97*),显著高于基线模型得分 79.53%。*

图 16 —测试准确率为 94.97%的训练结果

此外,虽然该分数是针对测试集的,而不是竞争中使用的最终测试数据,因此不能直接进行比较,但仍然需要注意的是,获胜模型的准确度分数为 82.02%。因此,我们可以假设上面概述的模型比获胜的模型表现得更好。

后续步骤

训练你自己的 word2vec

改进模型的一个方法是为自己的语料库训练自己的 word2vec。由于这需要一个非常大的数据集来训练,我们可以简单地导入 Google 的 word2vec,然后使用 TFIDF 嵌入来根据我们较小的数据集训练已经训练好的权重。

图 TFIDF 嵌入代码

为此,首先需要计算向量空间中的 TFIDF 值,这可以通过使用 TfidfVectorizer 轻松完成。

图 18 —构建 word2vec 的代码

一旦完成,然后你构建一个函数,根据之前计算的 TFIDF 矩阵更新 Google 的 word2vec 矩阵。

图 19 —建筑矩阵代码

然后,我们简单地使用新的权重将标记化的单词转换到向量空间。这一过程还允许用户跳过嵌入层,只需将输入馈入卷积层。

我们试图使用这种方法来构建一个更加定制化的 word2vector 空间,然而这一过程证明了其计算开销很大。因此,我们计划在项目的最后阶段这样做。

建立一个多标签多类的单一模型,而不是两个模型

我们可以改进该项目的另一种方法是使网络更类似于获胜模型的网络。这意味着将问题视为多标签多类问题,而不是两个单独的分类问题。

有两种方法可以做到这一点。(1)我们简单地不创建两个数据集作为同意数据集和相关数据集来馈入网络,而是简单地馈入具有多类、多标签目标变量的单个数据集。(2)我们仍然有两个网络,但是它们在做出预测之前收敛。最后一层是具有 4 个张量的稠密层,将问题视为多标签多类问题。

上采样

我们可以在相关模型中使用上采样,使数据集更加平衡。相关模型以 73%的准确度预测天平的准确度。数据的平衡已经达到 75%,其中 75%的数据集被归类为不相关。

附加数字

图 20 —与培训相关/无关的模型损失

图 21-训练标题-正文对模型损失

参考

训练 Google 的 Word2Vec 或创建自己的 word 2 vec 的两种不同技术。是部署技术的绝妙指南:https://towards data science . com/natural-language-processing-class ification-using-deep-learning-and-word 2 vec-50 cbad 3 BD 6a

**Github Repo 为竞赛中使用余弦连接的第三个最佳模型,当连接神经网络的输入时:https://github.com/uclnlp/fakenewschallenge

**解释 CNN 为什么以及如何与 NLP 任务一起工作:https://medium . com/saarthi-ai/sentence-class ification-using-convolutionary-neural-networks-ddad 72 c 7048 c

**编写多输入 keras 模型的文档:https://www . pyimagesearch . com/2019/02/04/keras-multiple-inputs-and-mixed-data/

**2013 年发表的开创性 Word2Vec 论文:https://arxiv.org/pdf/1301.3781.pdf

**为 NLP 任务编写多通道 keras 模型的文档:https://machine learning mastery . com/develop-n-gram-channel-convolutionary-neural-network-opinion-analysis/

**关于 NLP 如何在纯数学空间中与不同技术一起工作的解释:https://towardsdatascience . com/NLP-learning-series-part-1-text-preprocessing-methods-for-deep-learning-20085601684 b

**Github 的矢量器方法示例:https://Github . com/Cisco-Talos/fnc-1/blob/master/deep _ learning _ model/vectors . py

第三部分:孟加拉语。人工智能手写字形分类最终模型

原文:https://towardsdatascience.com/part-iii-bengali-ai-handwritten-grapheme-classification-final-model-725daee16102?source=collection_archive---------51-----------------------

总结和归纳我们的项目

工作主持人: 大卫·柯布迪杰森·卡茨迈克尔·哈德奈娜·沃顿**

查看系列第一部分

查看 Pat II 系列

最终模型笔记本

在过去的一个月里,我们一直致力于创建一个准确的孟加拉文字元分类器。虽然我们之前已经记录了我们的旅程(上面链接的以前的帖子),这里我们将快速总结我们的故事,并重新介绍手头任务的复杂性。

这个博客是为了进一步记录我们团队在提交孟加拉文的参赛作品时所做的努力。AI 手写字形分类大赛。我们建立了几个卷积神经网络(CNN ),可以根据元音发音、辅音发音和石墨烯根正确识别任何给定石墨烯的属性。虽然这项任务并不容易,但有许多公开可用的 Kaggle 内核说明了其他团队构建最佳模型的努力(链接如下)。

孟加拉语是世界上第五大通用语言,有大约 13,000 个不同的字形字符(见图 1)。孟加拉文字有三个不同的部分:11 个元音、7 个辅音和 168 个词根。这导致总共约 13,000 个可能的不同字符。作为参考,英语只有 250 个不同的字符。

图一(http://omniglot.com/writing/bengali.htm)

作为开发解决方案的第一步,我们需要决定要训练多少个模型。这些选项是(1)训练一个单一的模型,用 13,000 个可能的类别对一个孟加拉字符进行分类,或者(2)建立 3 个不同的模型,每个模型对辅音发音符号、元音发音符号和字素词根进行分类。第二个选项将类的数量减少到(168+7+11=) 186,因此我们决定使用这种方法。虽然我们可以构建三个不同的 CNN,但这是对计算能力和时间的浪费。相反,我们建立了一个具有三种不同成分输出的模型,从而对字素根、元音发音符号和辅音发音符号进行分类。

基线模型

下面引用了我们用来构建第一个模型的代码(参见图 2)。初始模型由具有 ReLU 激活和填充的 5 个卷积层组成,这确保了包含在边界像素上的信息被保留。第一层之后是批量标准化和最大池层。在第三和第五卷积层之后,应用另一个最大池层。在 max-pooling 层之后,该层被展平,然后是两个密集层,每个层的 ReLU 激活率和退出率都为 0.5。辍学是一种技术,通过这种技术,在训练期间,一定百分比的神经元(在这种情况下为 50%)被有效地杀死,从而迫使剩余的神经元学习得同样好并分散信息。剔除可以防止辨别能力集中在少数神经元中,并可以略微提高模型的整体准确性。如前所述,该模型对三种不同的输入进行分类:字素根、元音发音符号和辅音发音符号。这些不同组件的验证精度分别为 0.6710、0.9185 和 0.9209。虽然基线模型表现良好,但我们希望通过一些常见的启发式技术(如数据扩充、迁移学习和 CNN 结构建模)来提高准确性值。

图 2

数据增强

数据扩充是一种通过修改数据集中的现有图像来生成新图像的技术。此技术的目的是模拟可能出现在测试集中的可想象的图像,并在训练数据有限时生成数据。这些图像然后与原始图像一起用于训练 CNN。

现有的图像可以通过旋转、移动、反射和操纵颜色通道等技术来修改。下面的图 3 展示了水平和垂直移动图像的几个例子。虽然我们并不缺少图像,但我们希望数据扩充将提高我们模型的稳健性和准确性。不幸的是,数据扩充并没有改善我们模型的性能。这可能是因为字符是手写的,所以在训练集中已经有相当多的变化。

图 3

迁移学习

为了增加我们模型的强度,我们考虑利用迁移学习。通过训练一个已经训练好的模型,同时保持较低的级别不变(见图 4),我们希望在训练我们的模型时达到更高的精度和更高的效率。

图 4

在我们的迁移学习模型中有两种主要的方法。(1)我们训练一个模型,保存它,然后将它用作导入的模型,冻结它的更高层并用新数据训练它,(2)我们导入一个以前训练过的模型,并在其上运行一个新模型,通过改变输入/输出层来满足我们的需要。

尝试模型方法一;我们只使用了一部分训练数据(50%)来训练一个简单的模型。保存简单模型后,我们冻结了它的层,并在顶部添加了层,用于调整另一半数据(见图 5)。

图 5

这是一种迁移学习技术,可能会带来丰硕的成果。然而,我们看到这种技术的准确性和损失表现更差。这可能对我们没有帮助的一个原因是由于大量的目标类(186)。我们在流行的 MNIST 数据集上看到的成功例子总共只有 10 个目标类(见下面的链接)。

**在第二次尝试中,我们使用了一个先前训练过的模型来实现迁移学习(链接如下)。这个先前使用的模型使用 CMATERdb 数据库(也在下面链接)。它还使用了一个Conv2D—max pool—Conv2D—max pool—DropOut—FC—soft max(分类),自定义模型,其迁移学习模型包括一个 ResNet 结构。不幸的是,谷歌云计算和 Kaggle 中的内核未能编译新模型。

雷斯内特

当我们在迁移学习中了解到 GCP 无法编译我们的代码时,我们开始考虑可能的策略,以使模型的计算更有效。其中之一是剩余网络(或 ResNet)。在本系列的第二部分中,我们将深入解释 ResNet。需要注意的一个基本问题是,ResNet 整合了许多剩余学习模块(图 6)。虽然这个想法很有希望,但准确性分数比基线模型差 5%到 10%。

图 6(https://arxiv.org/abs/1512.03385)

最终型号

在尝试了各种方法后,我们提交给 Kaggle 竞赛的最终模型具有以下结构。首先,我们应用一个带有 ReLU 激活和填充的卷积层。接下来,有一个批处理规范化层,后跟一个最大池层。然后应用两个卷积层(都使用 ReLU 激活和填充),之后是最大池层。两个卷积层和一个最大汇集层的序列被应用两次以上。按照这个重复的顺序,在使用 ReLU 激活和删除的密集层之前应用展平层。应用具有 ReLU 激活和脱落的一个更密集的层。最后,根据网络认为图像属于的字符类型(字形根、元音发音符号或辅音发音符号),网络分成三个分支。根据该初始分类,应用具有 softmax 激活的最终密集层,其中神经元的数量与相应字符类型中的类的数量相匹配。代码和网络结构可分别参考图 7 和图 8。

图 7

图 8

字形根分类任务在我们的最终模型中具有最低的准确性,对于训练集为 0.7973,对于验证集为 0.7718(参见图 9)。正如在以前的帖子中提到的,这是有意义的,因为这个字素根有 168 个类要正确分类。

图 9

最终的模型对于元音发音符号的训练精度为 0.9496,验证精度为 0.9277(见图 10)。最后,辅音发音符号的训练精度为 0.9557,验证精度为 0.9373(参见图 11)。

图 10

图 11

考虑到手头的重要任务,我们的团队对我们的最终模型非常满意。如果我们能在这个项目上花更多的时间,我们可以通过适当地利用 GCP 来进一步改善我们的 CNN。这将允许我们在更多的时期训练我们的模型,测试更广泛的超参数,并进一步探索我们的迁移学习道路。

资源:

用于基线模型的笔记本:https://www . ka ggle . com/deshwalmahesh/Bengali-ai-complete-beginner-tutorial-95-ACC/data,https://www . ka ggle . com/chekoduadarsh/tutorial-design-your-own-CNN-layer-by-layer,https://www . ka ggle . com/chekoduadarsh/multi-output-CNN-starter-kit【T9

笔记本咨询了 EDA:https://www . ka ggle . com/kaushal 2896/Bengali-graphemes-starter-EDA-multi-output-CNN、https://www.kaggle.com/pestipeti/bengali-quick-eda、https://www . ka ggle . com/gp reda/Bengali-ai-handled-grapheme-getting-started

数据增强:https://machine learning mastery . com/how-to-configure-image-Data-Augmentation-when-training-deep-learning-neural-networks/、https://keras.io/preprocessing/image/、https://towards Data science . com/exploring-image-Data-Augmentation-with-keras-and-tensor flow-a 8162d 89 b 844

转学:https://keras.io/examples/mnist_transfer_cnn/,https://arxiv.org/html/1902.11133,https://github.com/swagato-c/bangla-hwcr-present

ResNet:https://www . research gate . net/figure/Natural-scenes-and-curvature-detection-a-photo-of-Torsten-Wiesel-and-David-Hubel _ fig 1 _ 311479268,https://machine learning mastery . com/how-to-implement-major-architecture-innovations-for-convolutionary-neural-networks/,https://arxiv.org/abs/1512.03385,

第三部分:利用人工智能打击假新闻的最终模式

原文:https://towardsdatascience.com/part-iii-using-a-i-to-combat-fake-news-final-model-933f75657ae0?source=collection_archive---------55-----------------------

总结项目过程和最终模型创建

工作主持人: 大卫·柯布迪贾森·卡茨迈克尔·哈德奈娜·沃顿**

第一部: 利用人工智能打击假新闻

第二部: 利用人工智能打击假新闻建模更新

在过去的一个月里,我们的团队一直致力于建立一个模型来准确地对假新闻进行分类。这个项目已被记录至今(上面链接);然而,在这篇文章中,我们将总结我们的工作,并讨论我们的最终模型。

工作

在假新闻挑战赛中,竞争对手获得了标记数据,并承担了创建姿态检测 ML 分类模型的任务。姿态检测是人工智能管道对假新闻进行分类的第一步,是确定新闻标题与其相应正文之间关系的过程。姿态检测中用于描述标题和正文之间关系的类别通常有:同意、不同意、讨论和不相关。竞赛网站为参赛选手提供训练集和测试集,以及加权准确率达到 79.53%的基线 GradientBoosting 分类器。该任务是一个多标签多类问题,模型需要首先决定标题和正文是相关还是不相关**。然后,如果两者有关联,把他们的关系归类为同意不同意或者讨论。提交给竞赛的模型以加权平均进行评估,25%的权重用于将正文和标题正确分类为不相关,75%的权重用于将模型分类为同意、不同意或讨论。**

图 1 —竞赛的评分结构

比赛于 2016 年举办;然而,鉴于深度学习的进步和我们社会中假新闻的剩余存在,我们的目标是创建一个可以超越竞争获胜模型的姿态检测模型。如果我们获得成功,我们的模型可能会被用于更广泛的人工智能管道,用于对假新闻进行分类。

电子设计自动化(Electronic Design Automation)

当生成任何 ML 模型或深度学习网络时,第一步通常是 EDA。竞赛提供了两个 csv 文件,一个包含正文,另一个包含它们的标记姿态。为了更好地理解数据,我们首先合并了两个数据集。最终合并的熊猫数据框架有 49972 条观察结果,具有三个特征:文章主体、标题和立场。数据集相当不平衡,因为与无关的标签约占数据的 75%。

图 2 —站姿计数的条形图。这是一个不平衡的数据集。

EDA 带来的另一个有趣的事情是,训练数据有许多不同的标题链接到相同的正文。考虑到来自不同出版物的不同作者经常报道相同的新闻主题(相同文本的不同标题),这是有意义的。该数据集包含 1,683 篇独特文章的 49,972 个标题,平均每篇文章约 30 个标题。然而,在进一步挖掘之后,很明显有些文章比其他文章更频繁地被“改变用途”。下图显示了一个文本正文被“改变用途”了 78 次,但是,一般来说,数据集主要包含唯一的标题和正文对。如果你想更深入地了解我们的 EDA 过程,请参考我们在这个系列中的第一篇文章(第一部分)。

图 3 —每个正文标题数量的直方图

竞赛获奖模型

接下来,我们想检查一下竞赛获胜模型,以此作为起点。赢得假新闻挑战的模型是两个模型之间的加权平均值:梯度推进决策树和卷积神经网络(CNN)。深度 CNN 使用嵌入应用于标题和正文。嵌入应用谷歌新闻预训练向量。卷积层的输出被发送到具有四级输出的 MLP。这四类是我们的四个量词:同意、不同意、讨论和无关。他们的模型在所有卷积层中使用概率为 50%的丢失进行正则化。他们的超参数被设置为逻辑默认值,但没有被评估来优化他们的网络。他们的 CNN 结构在下图中有进一步的描述。

图 4 —竞争获胜的 CNN 模型结构(https://github . com/Cisco-Talos/fnc-1/tree/master/deep _ learning _ model)

获胜提交的第二部分加权平均是一个决策树模型。该模型接受来自文章标题和正文的基于文本的特征的输入。这些输入被输入到梯度推进决策树中,以预测标题和正文之间的关系(同意、不同意、讨论或不相关)。下图概述了这种模型结构。这个决策树模型的输入非常依赖于特征工程。获奖模型的创作者通过预处理(generateFeatures.py)、基本计数特征(CountFeatureGenerator.py)、TF-IDF 特征(TfidfFeatureGenerator.py)、SVD 特征(SvdFeatureGenerator.py)、Word2Vec 特征(Word2VecFeatureGenerator.py)和情感特征(SentimentFeatureGenerator.py)进行特征工程。

图 5 —赢得竞赛的 XGBoost 模型结构(https://github.com/Cisco-Talos/fnc-1/tree/master/tree_model)

初始模型

在改进竞赛获奖模型的最初尝试中,我们采取了两个步骤:我们重新定义了分类问题,并将工程特征纳入 CNN。

竞赛定义的问题,如上所述,本质上是一个多标签多类问题。但是,我们选择了稍微不同的解决方法。我们将问题分成两部分,针对两种不同的分类问题训练模型。

第一个模型是分类标题和正文是相关还是不相关。这个模型包括标题、正文、工程特征和标签。需要注意的是,比赛给出的数据没有任何与相关的标签名称。我们简单地创建了一个新的数据集,用标签 related 代替agree/disagree/discussion*。然后使用第二个模型将身体和头部之间的关系分类为同意/不同意/讨论。这两个模型在结构上是相同的,只是它们的分类任务不同。***

图 6 —具有三个输入的初始模型架构。一个是标题的卷积层,一个是正文的卷积层,一个是工程特征的密集层。

如上面概述的模型架构所示,我们的网络包括由密集层组成的第三个输入。这个额外的网络输入取代了优胜模型中 XGBoost 的使用。输入将是一个n×3矩阵,其中 n 是观察的数量,3 代表三个工程特征:["fk_scores "、" word_count "、" num_grammar_errors"]。所有这三个特征都是针对身体的。fk_score 是一个广泛使用的语言指标,用来衡量文章所用语言的复杂程度。

卷积网络(模型的输入 1 和输入 2)遵循具有两个卷积层的简单架构。它们输出具有 34 个张量的密集层,然后连接到连接层。嵌入层作为网络的第一层,使用之前使用 Google 的 Word2vec 计算的嵌入权重进行初始化。在我们训练嵌入权重之前,我们处理数据以去除标点符号,然后对文本进行标记。最后,完成架构的密集层和批量标准化(如上图所示)也遵循简单的结构。这个初始模型的结果很好。使用竞赛规定的准确度分数计算;我们的总体加权准确率为 89.51%,显著高于基线模型的 79.53%。此外,该分数是针对测试集的,而不是竞赛中使用的最终测试数据。因此,我们不能直接将我们的结果与获胜模型的结果进行比较。然而,考虑获胜模型的 82.02%的准确度分数仍然是有用的。这个初始模型及其结果在本系列的第二篇文章(第二部分)中有更深入的介绍。

最终型号

正如本系列第二部分所建议的,我们希望使用上采样来重新平衡数据集,以便我们的神经网络可以更好地分类不相关和相关的标题-正文对。数据集的平衡非常偏向于不相关的标签,这大约占数据的 75%。注意,在前面的模型中,我们将正确分类不同标签的任务分成了两个不同的任务。第一个神经网络的测试准确度分数为 73.13%,略低于数据集的平衡,因此似乎对数据进行上采样可以提高该模型的准确度分数。然而,经过进一步的考虑,我们意识到对数据进行向上采样是没有意义的,因为现实生活中的数据在各个类别之间不会有均匀的分布。此外,如果我们期望真实生活数据来自分布,那么使用上采样技术是没有意义的。除此之外,上采样涉及模拟新数据,考虑到数据的性质需要生成文本,这将非常耗费时间。因此,鉴于我们不知道不同阶层的真实分布情况,对少数阶层进行抽样调查是没有意义的。

虽然我们最终决定不对数据进行上采样,但我们确实训练了 Word2Vec 嵌入。在我们模型的前一次迭代中,我们使用了 Google 的 Word2Vec 嵌入,它是在报纸文章上训练的。虽然这种嵌入非常好,并且已经在万亿字节的数据上进行了训练,但它并没有针对我们正在使用的数据进行个性化。训练我们自己的对数据集唯一的 Word2Vec 嵌入也没有意义,因为我们缺乏这样做的数据量。因此,一个方便且易于实现的解决方案是稍微修改 Google 的 Word2Vec 嵌入。我们为标题和正文创建了两个词频逆文档频率(TFIDF)矩阵。TF-IDF 是一种衡量一个单词在一个更大的短语的上下文中的相对重要性的方法。然后将 TF-IDF 矩阵与 Google 的 Word2Vec 嵌入相乘,以重新加权嵌入。换句话说,重新加权嵌入= TF-IDF 矩阵 Word2Vec 嵌入。下面提供了相关的代码。*

图 7 —训练 TFIDF 矩阵的代码

图 8 —使用 TFIDF 创建嵌入权重的嵌入函数

除了重新加权 Word2Vec 嵌入,我们还重新设计了神经网络的结构。之前,我们将多级分类问题视为两个独立的模型,第一个模型区分相关和不相关的标题-正文对,第二个模型区分以下类别:同意、不同意和讨论。虽然这两个模型结合起来表现得相当好,但解决方案效率相当低。不仅训练两个模型花费了更多的时间,而且训练两个模型也不是合适的解决方案,因为第二个神经网络不能利用来自第一个模型的权重来改进对第二级标签进行分类的决策过程。此外,该问题的原始设计是一个多级多标签分类问题,因此我们认为坚持这种结构将提高模型的准确性得分。

而且,这个模型与之前的模型不同,因为它没有使用 CNN。代替 CNN 层,该模型具有双向 GRU 细胞。GRU 细胞是一种更复杂的版本,或者是一种循环神经细胞。GRU 细胞被设计成避免短期记忆的问题,在短期记忆中,细胞将只记住并考虑最近的输入。当大的文本序列被输入一个递归神经细胞时,该细胞可能只记住文本末尾的重要信息。GRU 细胞通过使用门来解决这个问题,因此可以更好地记住并跟踪一长串文本中的重要信息。在我们的模型中,我们使用双向 GRU 单元,因此文本通过该单元向前和向后处理,以更好地确定序列中的重要单词。

由于这些变化,我们的模型最初每个时期需要 15 个小时来训练,即使我们的数据集非常小。为了减少我们模型的训练时间,我们将批量大小从默认的 32 增加到 128,同时将输入的最大序列长度(考虑的单词数)从 4,600 减少到 1000。通过查看下面的图 9,我们决定将最大序列长度减少到 1000。从直方图可以看出,正文超过 1000 字的文章很少。我们还查看了标题中的字数,但是我们决定不需要减少最大序列长度(参见图 10)。

图 9 —文章正文长度直方图。正文中的字数太多,无法合理地输入神经网络。假设数据的分布通常上限为 1,000;我们将输入限制为字数少于 1000 的任何内容。

图 10 —文章标题长度直方图。每个标题中的字数是一个在神经网络中处理的合理数字。

下面以两种不同的方式展示了最终的模型结构:一个图表,一个层表(图 11 和图 12)。正如我们在下面看到的,这个模型和以前的模型的最大区别是,这个模型有双向 GRU 层而不是卷积层,并且这个模型是一个多级多类神经网络。

图 11 —最终模型结构

图 12 —最终模型结构图。这个模型又有三个输入,然而,它们如下:一个具有用于标题的双向 GRU 层,一个具有用于主体的双向 GRU 层,一个具有用于工程特征的密集层。

正如我们之前所做的,该模型在 39,977 个观察值上进行训练,并在 9,995 个观察值上进行验证。由于训练模型的密集时间成本,我们训练了 5 个时期的模型。将来,如果我们增加模型接受训练的时期数,模型的性能可能会更好。经过 5 个时期后,模型的训练准确率为 92.16%,测试准确率为 90.51%。这些值比之前 89.51%的准确率提高了 1.1%。虽然最终模型的准确性得分确实有所提高,但考虑到我们实施的变更数量,它并不像我们预期的那样显著。尽管如此,改善还是很显著的。

图 13 —测试准确度为 90.51%的最终模型训练结果

图 14-最终模型训练损失结果

潜在的改进

虽然我们对这些模型结果非常满意,但总有改进的余地。通过对更多数据进行训练,通过向模型添加层来试验更深的网络,或者尝试向模型中加入额外的或替代的工程特征,可以对我们的模型进行潜在的增强。

参考

训练 Google 的 Word2Vec 或创建自己的 word 2 vec 的两种不同技术。是部署技术的绝妙指南:https://towards data science . com/natural-language-processing-class ification-using-deep-learning-and-word 2 vec-50 cbad 3 BD 6a

**Github Repo 为竞赛中使用余弦连接的第三个最佳模型,当连接神经网络的输入时:https://github.com/uclnlp/fakenewschallenge

**编写多输入 keras 模型的文档:https://www . pyimagesearch . com/2019/02/04/keras-multiple-inputs-and-mixed-data/

**2013 年发表的开创性 Word2Vec 论文:【https://arxiv.org/pdf/1301.3781.pdf】

**为 NLP 任务编写多通道 keras 模型的文档:https://machinelingmastery . com/develop-n-gram-channel-卷积-神经网络-情感分析/

**关于 NLP 如何在纯数学空间中与不同技术一起工作的解释:https://towardsdatascience . com/NLP-learning-series-part-1-text-preprocessing-methods-for-deep-learning-20085601684 b

**Github 的矢量器方法示例:https://Github . com/Cisco-Talos/fnc-1/blob/master/deep _ learning _ model/vectors . py

**训练时如何让 RNNS 和 CNN 一样快:https://openreview.net/forum?id=rJBiunlAW

**双向 GRU 图层文档:https://www . tensor flow . org/API _ docs/python/TF/keras/layers/Bidirectional

偏相关与相互作用信息

原文:https://towardsdatascience.com/partial-correlation-vs-conditional-mutual-information-c7feffa9b88e?source=collection_archive---------29-----------------------

偏相关和交互信息是评估数据集中混杂变量之间关系的两个强大工具

在数据分析任务中寻找数据集中不同变量或要素之间的关系是数据科学家应该掌握的关键和基本技能之一。

在这篇短文中,我们将介绍一个你在研究和分析问题时可能遇到(也可能没有遇到)的现象。我们将创建一个简单的数据集,并应用我们的指标来发现这一现象并进行讨论。

在我们的数据集中找到变量之间的关系对于去除冗余变量进行预测、推断因果关系(如果可能的话)是至关重要的。)并大致了解我们的数据集在解释我们的假设方面有多丰富。

出现的一个主要问题是不同随机变量的相关性。我们可以使用相关矩阵、线性拟合和其他不同的方法来找出关系,并在我们认为合适的时候使用,从而解决这个问题。但是,如果我们有两个变量,我们认为它们之间有很强的相关性,但事实是它们都与第三个变量密切相关,而第三个变量增加了这种关系的强度,那该怎么办呢?

这个问题可能会破坏我们的假设,迫使我们对自己(和我们的上级……)撒谎。

X 和 Z 以及 Y 和 Z 的独立关系对 X 和 Y 的关系有什么影响

解决这个问题的一种可能的方法是使用一种叫做“部分相关”的方法。

与皮尔逊相关相比,偏相关考虑到了第三个变量的存在并“控制”它。

控制一个变量是什么意思?

在因果模型中,对变量的控制意味着根据变量的测量值的宁滨数据。这通常是为了使变量不再成为混杂因素,例如在观察性研究或实验中。

这样做的正式方法是在 X 和 Z 以及 Y 和 Z 之间进行线性回归,收集误差项,并在误差项之间使用标准皮尔逊相关。当我们想到这一点时,如果 X 和 Y 与 Z 无关,那么它们各自对 Z 的线性回归的误差将彼此相关(更高的偏相关)。如果误差项不同(较低的偏相关),这意味着 X 和 Y 与混杂因素(Z)具有不同的关系,并以两种不同的方式受其影响,因此当考虑 Z 时,它们之间的关系(X 和 Y)应该较低。

用 Z 找出两个线性回归的 Wx 和 Wy 系数,<_>代表标量积,维基百科

错误术语的定义,维基百科

偏相关的定义,维基百科

让我们看一个例子。

首先,我们将导入相关的库并创建一个简单的数据集。

import numpy as np
from scipy import stats, linalg
import matplotlib.pyplot as plt
import randomrandom.seed( 30 )
mu1 = 2
sigma1 = 2
x = np.arange(100)
p1 =  np.random.normal(mu1,sigma1,100)
p2 = np.square(p1) + 3
p3 = np.power(p1,3) + 2 plt.figure
plt.plot(x, p1, 'r--',x, p2, 'g--',x, p3, 'b--')
plt.xlim(0, 40)
plt.ylim(-1, 50)

三个随机变量 p1、p2 和 p3

如你所见,我创建了 p2 和 p3,使它们基于 p1。p2 是 p1 加上一个常数的平方,p3 是 p1 加上一个常数的 3 的幂。让我们天真地检查 p2 和 p3 之间的皮尔逊相关性。

np.corrcoef(p2,p3)array([[1\.        , 0.91533677],[0.91533677, 1\.        ]])

因此,我们有一个 0.91 的相关性,如果我们看一下上图中的蓝线和绿线,这是有意义的,两个变量的趋势是一致的。

让我们使用我们之前描述的偏相关公式来检查 p2 和 p3 的偏相关,将 p1 视为控制变量。

def partial_corr(p1,p2,p3):p1k = np.expand_dims(p1, axis=1)p2k = np.expand_dims(p2, axis=1)p3k = np.expand_dims(p3, axis=1)beta_p2k = linalg.lstsq(p1k, p2k)[0]  # Calculating Weights (W*)beta_p3k = linalg.lstsq(p1k, p3k)[0]  # Calculating Weights(W*) res_p2k = p2k - p1k.dot(beta_p2k) # Calculating Errorsres_p3k = p3k - p1k.dot(beta_p3k) # Calculating Errorscorr = stats.pearsonr(np.squeeze(res_p2k), np.squeeze(res_p3k))[0]return corrpartial_corr(p1,p2,p3)0.7327481408542633

p2 和 p3 之间的相关性为 0.73。我们可以看到,这种相关性低于我们之前认为的(0.91),因为变量 p1 以不同的方式与它们相关。这反过来又导致两个变量的误差项不同,结果,部分相关性将更低。

可能有许多使用这种相关性度量的例子。
你可以在行为科学和气候变化分析中看到它们。

现在让我们讨论离散随机变量情况下的另一种类似技术,条件互信息。

信息论中的互信息描述了两个随机变量之间的相互依赖关系。它比皮尔逊相关系数更普遍,因为它不需要线性关系和实值随机变量。MI 的概念与从信息论中更熟悉的熵密切相关。

给定 p2,p2 和 p3 之间的互信息是 p3 的熵减去 p3 的条件熵

现在假设我们有第三个变量,我们希望在两个变量之间的互信息估计中考虑这个变量。我们希望使用一种类似于偏相关的技术,来修正我们的估计,并给出它们三者之间相互作用的提示。

让我们首先定义另一个称为条件互信息(CMI)的度量:

条件互信息方程

我们将使用一种称为交互信息的度量,它是 MI 的一种推广。p1、p2 和 p3 之间交互信息的正式定义是:

交互信息的定义其中 I(p2,p3)是 p2 和 p3 之间的 MI,I(p2,p3|p1)是这些变量之间给定的条件 M I。

在这篇文章中,我不会进入 MI 和条件 MI 的严格数学定义,但你可以查看我之前附上的链接。

让我们举一个简短的例子来理解直觉:

假设我们前面例子中的 P1 是 100 天内测量的天空中的云量。我们还假设 P2 是用离散的光度计测量的 100 天的黑暗水平(黑暗的程度受云量的影响), P3 是 100 天的降雨量,以毫升为单位。

让我们使用我们的变量来计算 MI、条件 MI 和交互信息,以便更好地理解。

from pyitlib import discrete_random_variable as drvp1 = np.round(p1) # to get integer values
p2 = np.round(p2) # to get integer values
p3 = np.round(p3) # to get integer valuesMI = drv.information_mutual(p2,p3)
MI3.676603187392168CMI = drv.information_mutual_conditional(p2,p3,p1)
CMI1.35947929InteractionInformation = MI - CMI
InteractionInformation2.317123892473724

因此,我们得到了比条件 MI ( 1.35)更大的 MI (3.67),结果得到了交互信息(2.31)。

我们能解释一下吗?

正如我们所知,云(p1)会导致雨(p2)和黑暗(p3),所以黑暗和雨之间的关系(或信息量)会受到云的影响。所以:

这将产生一个积极的互动信息,正如我们之前定义的那样!

人们应该小心解释相互作用信息,因为它也可能具有负值,并且从中得出的结论可能是棘手的(如在相关/部分相关中)。这也是为什么它在数据科学社区中不经常被用作评估随机变量之间关系的通用指标。

我们在这里介绍了两种不同的方法来评估混杂随机变量之间的相互作用:偏相关和相互作用信息。我使用了离散和连续变量来展示不同设置下的应用。这些方法更加“微妙”,因为它们要求对您的数据非常熟悉,所以要注意这一点。

你可以通过 zeogod@gmail.com 给我发评论或者关注我的 Github 页面。

参考资料:

  1. 来自 Fabian Pedregosa 的偏相关函数实现
  2. 维基百科(一个基于 wiki 技术的多语言的百科全书协作计划ˌ也是一部用不同语言写成的网络百科全书ˌ 其目标及宗旨是为全人类提供自由的百科全书)ˌ开放性的百科全书
  3. 广义线性模型中交互效应筛选的相关、偏相关和条件互信息比较,李稷阿肯色大学费耶特维尔 2018— 链接
  4. https://pypi.org/project/pyitlib/—用于处理离散随机变量和信息论函数的 python 包

Python 中的部分函数

原文:https://towardsdatascience.com/partial-functions-in-python-4441270df1e8?source=collection_archive---------13-----------------------

降低代码的复杂性。

来源

在这篇文章中,我将谈论部分函数,以及我们如何使用它们来使我们的代码更整洁。

部分函数能为我们做什么?

分部函数允许我们调用第二个函数,在某些参数中使用固定值。例如,我们可能有一个计算指数的函数。然后,我们可能需要创建一个新的函数,为底数或指数分配一个固定值。我们可以通过使用 functool 的部分函数轻松做到这一点,而不必复制原始函数的主体。让我们通过上面例子的实现来更好的理解。

实现部分取幂函数

首先,我们需要分部函数所基于的函数。如前所述,我们将实现一个求幂函数:

def power(base, exponent):return base ** exponent

现在,我们可能想要实现一个函数来计算一个数的平方值。如果 Python 中没有可用的部分函数,我们就必须复制(和修改)我们的代码:

def squared(base):return base ** 2

在这种情况下,这没什么大不了的,因为我们只需要复制一行代码。然而,在大多数情况下,您将不得不处理更大的函数。让我们看看如何通过部分函数重用“power()”:

from functools import partialdef power(base, exponent):return base ** exponentsquared = partial(power, exponent=2)

最后,我们可以简单地调用“squared()”如下:

squared(3)
squared(base=7)

就是这样!我希望分部函数成为您的有用工具,帮助您降低代码的复杂性!

缺乏采用将继续抑制人工智能/人工智能的发展

原文:https://towardsdatascience.com/participation-the-underserved-mindset-stifling-ai-ml-progress-2d22bac94156?source=collection_archive---------40-----------------------

为什么我们需要超越商业承诺

尼古拉·特尔萨在 1926 年预言了“智能手机”

T 这里可能有成千上万的数据科学家、分析师和机器学习工程师。努力解决一些与数据相关的业务问题……并且可能对清理数据所花费的不公平的时间感到沮丧。

此外,还有分析公司 Gartner。他们调查了高达 80%的人工智能/人工智能项目失败。这让我们感觉不那么孤独,因为我们的失败率似乎在同一范围内!

但是什么样的项目是注定的呢?

产生了哪些不够好的见解?这种情况是否更多发生在节省成本而非创造收入的项目上?在金融、公用事业、媒体等垂直行业中,差异有多大?

以电信为例。今天,全世界大约有 800 个移动网络连接着 60 亿付得起钱的人。3G、4G 和 5G 技术让我们无论身在何处都能使用 Whatsapp、Instagram 或 Zoom 以及我们的身体移动方式

这些网络需要多年的 R&D 和巨额资本才能实现。新系统可能会给我们带来更低的延迟和更高的带宽,但它们也使网络变得更加复杂、昂贵和难以管理。没有人能预测消费者会如何使用他们的移动设备,他们需要什么样的带宽。

但是,尽管不断有 AI/ML 驱动的产品尝试自动化操作任务并产生预测性见解,大多数无线网络仍然需要大量的人工干预。

而这些 AI/ML 产品承诺了什么?

第一,商业承诺。解决棘手问题,降低成本,增加收入。在那之后,可能会有人类的承诺。让生活更轻松,节省时间,提高技能。

正是这第二个承诺不那么有形…不那么黑白分明…不那么明确。

零接触网络的总体目标是让机器学习如何变得更加自主,以便我们可以将复杂、平凡的任务委派给它们。为什么?它为人类腾出了更多的时间来做我们擅长的事情——执行需要更深入理解的更复杂的任务——埃琳娜·费尔斯曼,爱立信(2019)

我们在大多数人工智能/人工智能演示文稿中都发现了这种情绪,但最后一句话敲响了一些警钟。这让我们想起了多年前在工程外包行业听到的一句令人不快的话。

  1. 将可重复、低价值的工作转移到成本更低的公司或地点
  2. 追加销售关于额外优势的业务案例,即腾出时间进行创新和高价值工作

但是在技术外包方面花了 8 年时间,我们不确定#2 是否曾经实现过。

人类的承诺有缺陷吗?

毫无疑问,昂贵的数字化改造项目风靡一时,试图让用户掌握应对不断变化的环境的技能。

但是当评估不确定性是变化的关键部分时会发生什么呢?即预测可信吗?别介意我们之前是凭直觉做出的决定。现在考虑 100 个数据点,结果真的更好吗?不要介意我们之前只使用了 2-3 个数据点。

想象一下,在这样一个环境中,定制工具、电子表格和经验已经融入决策制定多年了。现在被要求根据黑盒的输出做出决定,黑盒带有 wtf,如模型准确性、相关性分数、混淆矩阵…

技术外包发生了什么

前提是,如果设计正确,新的后外包世界将更具创新性、更有效率、更具成本效益……甚至更好。

一旦工作移交完毕,剩下的工作人员通常有两种选择:

  1. “管理”现在工作的团队
  2. 继续做无法外包的更复杂的工作

然而,失败是很多的,并且通常围绕管理范围和服务水平。因为在大多数情况下,我们希望外包团队像我们一样完成工作。

如果他们以其他方式做到了,我们根本无法让自己相信结果。

有了 AI/ML,感觉历史在重演。

我们不想看到的是

我们领域中的大多数终端用户不是数据科学家,尽管他们可能有数据科学经验。他们既不是统计学家也不是分析师,但熟悉这些概念。他们是执行高度技术性工作的人,现在看到这种工作在一定程度上实现了自动化,其结果是他们所期望的信任…和补充。

从数据科学的角度来看,我们经常犯结果第一,采用第二的错误。用户对的感受并不是我们花了很多时间去考虑的事情。

但是在湾区与独一无二的王戈的偶遇给了我们一些思考的素材。

[## 循环中的人类

交互式人工智能系统的设计

medium.com](https://medium.com/artful-design/humans-in-the-loop-b83e3bffa65e)

如果我们不认为自动化是从任务中去除人类的参与,而是想象它是人类参与的选择性包含,会怎么样?反过来,我们拓宽了“我们如何建立一个更智能的系统?”到“我们如何将有用的、有意义的人类互动整合到系统中?”

有意识地为参与而设计

事后看来,我们长时间被缺乏意识蒙蔽了双眼。我们忽略了对终端用户的考虑,以及他们如何逐渐但有意义地互动。

所以我们做了两件事,但现在是通过参与的角度。

1.了解我们的用户之旅(可用性)

对我们来说,客户甚至是那些熟悉数据科学的人经常会提出类似的问题。从“你是如何得到这些结果的?”到“我们能看到使用的原始数据吗?”然后“你能解释一下其中的取舍吗”?…但总是以“我们真的能相信这些结果吗?”。

因此,我们试图将这些反馈分解为以下内容:

  1. 用户会看到什么结果?
  2. 这是他们可以利用的结果吗?
  3. 他们会对这一结果提出什么问题?
  4. 我们需要采取什么步骤来解释这个结果?

在多次尝试重新设计我们的 UI 之后,很明显我们正在努力提供简单灵活的后处理数据可视化来支持这些问题。datascape 变化太快了。

因此,我们最终推出了一个混合用户界面,它可以整合 Tableau 等 BI 工具来进行数据解释和分析……只是为了让用户能够在没有陡峭的学习曲线的情况下提问。这确实意味着要更加仔细地进行后 ML 数据设计,以应对 BI 限制,但迄今为止,这种权衡似乎是合理的。

但是,尽管所有的分析分层和构建故事板的尝试,我们努力解释人工智能/人工智能的结果。这推动我们走向系统化。

2.围绕用户的数据之旅构建系统(可解释性)

一旦我们对用户的旅程有所了解,我们就开始考虑如何将不同的数据组件连贯地拼凑在一起。

Loraine Lawson 谈到了基础分析和了解数据起点的重要性。令人惊讶的是,这是最难的部分……考虑到大量数据输入和重叠信息,从哪里开始。难怪用户在经历多种渠道后,很难将产出与现在几乎无法识别的输入数据关联起来。

不过,我们确实看到了一个高级系统是如何让从数据到结果的过程变得不那么令人生畏的…而且更有把握,也就是说,如果我们遵循这些“步骤”,这就是它的含义,我们很可能会有所收获!

最后的想法

[## 社会企业家莱拉·贾纳去世,享年 37 岁。她用一个简单的想法改变了 5 万人的生活

非洲的人们需要工作,公司需要人们为 AI 输入数据。真是绝配。

medium.com](https://medium.com/inc./social-entrepreneur-leila-janah-is-dead-at-37-she-changed-the-lives-of-50-000-with-a-simple-idea-af304f30e788)

像 Digital Data Divide 和 Samasource (已故的 Leila Janah 是他们的 CEO)这样的公司在多年前就开创了将 AI 训练数据准备外包给低成本国家的先河。

人们可能会质疑潜在的动机,但不管怎么说,它确实使以前获得人工智能/人工智能类型技术的手段有限的服务不足的人口成为可能。

对于正在自动化或沿着 AI/ML 道路前进的高技术工作,我们已经看到技术熟练的人适应起来有多难。我们大多数项目的失败是因为用户没有参与到过程中,没有参与到结果中,也没有意识到结果对他们来说意味着什么。为什么?我们只是在帮助他们方面做得不够好。

数据科学和 AI/ML 会改变世界吗因为它可以解决难题、提高效率和降低成本?还是因为它发现让外围的人成为过程的一部分很重要?

同样,也许我们之前谈到的 800+移动网络不仅仅是连接人们,而是给 60 亿人一个参与的机会。

(2020 年 4 月)鱼在潮湿多风的环境中啃食加州拉霍亚

欧洲粒子物理研究所用机器学习进行粒子跟踪

原文:https://towardsdatascience.com/particle-tracking-at-cern-with-machine-learning-4cb6b255613c?source=collection_archive---------15-----------------------

CMS 探测器中模拟的高能碰撞,L. Taylor — CERN PhotoLab

机器学习可以在高能物理中用于发现和表征新粒子吗?

TrackML 是 2018 年的一场 Kaggle 比赛,奖金为 25 000 美元,挑战是从硅探测器中留下的 3D 点重建粒子轨迹。 CERN (欧洲核研究组织)提供了粒子碰撞事件的数据。它们在那里发生的频率大约是每秒几亿次碰撞,或者每年几十千兆字节。在筛选如此大量的数据时,显然需要尽可能高效,这就是机器学习方法可能有所帮助的地方。

背景

粒子,在这种情况下是质子,在大型强子对撞机(LHC)中被提升到高能量——当碰撞时,每束可以达到 6.5 TeV,总共 13 TeV。电磁场被用来加速 27 公里长环路中的带电质子。当质子束碰撞时,它们会产生各种各样的亚原子副产品,这些副产品会迅速衰变,为一些最基本的物理学问题提供有价值的信息。

探测器由一层层的子探测器组成,每个子探测器都被设计用来寻找特定的粒子或特性。有测量能量的量热仪、确定粒子种类的粒子识别探测器和计算粒子路径的跟踪装置。我们当然对跟踪部分感兴趣,当粒子通过这些类型的探测器时,微小的电信号被记录下来。我将讨论的是重建这些记录的轨迹模式的方法,特别是涉及机器学习的算法。

数据

由于目的是将机器学习应用于数据,CERN 的人员将其分为训练集和测试集,以便验证模型。训练数据集包含粒子的初始参数及其记录的命中,以及生成粒子和命中之间的映射。测试数据只有记录的点击。然后,我们剩下的任务是将每次点击与一个音轨相关联。

我读到 2020 年是我们应该与图表互动的一年,所以这里是探测器中使用 Plotly 的 10 000 次点击的样子:

LHC 的粒子观测

根据它们的 layer_id 对命中进行着色,layer_id 是检测器层的数字标识符。坐标以毫米为单位,因此我们在这里考虑的探测器部分大约有三米长,横截面大约为一平方米。粒子需要通过不同的层来追踪,为了更好地理解轨迹可能的样子,我直接从训练数据中绘制了一些轨迹。我们可以看到,大多数粒子从原点出发,也就是碰撞发生的地方。

训练集中的实际粒子轨迹

螺旋聚类

我们可以做一些巧妙的预处理,利用大多数轨迹遵循螺旋模式的假设,使数据更有序。这是因为存在磁场,否则粒子会直线运动。粒子动量也会影响螺旋的紧密程度,动量越高,轨迹就越直。我们可以通过首先获得距离来说明曲率

然后用击中坐标除以它。这将使同一轨迹上的点相互靠近。

我们可以在训练数据上验证我们的假设,其中我们知道整个检测器中的粒子 id。因此,如果我们在应用螺旋变换之前以及之后可视化一些粒子的轨迹,我们可以清楚地看到集群出现。这意味着许多粒子像假设的那样在 z 方向上以螺旋模式行进。

与预处理时相比的点击横截面

这提供了在数据上使用聚类来将轨迹分组到某个原始粒子的机会。DBSCAN(带噪声的应用程序的基于密度的空间聚类)可用于此目的。该方法用 Python 编写,可转换为以下代码片段:

标准缩放器减去平均值并缩放到单位方差,它用于通过标准化变量来提高聚类的性能。特征缩放是机器学习预处理过程中的一个常见步骤。scaler 和 DBSCAN 都是从 scikit learn 导入的,还有一个定制的 TrackML 库用于处理加载事件或洗牌等。此处未显示。在任何情况下,在使用 eps=0.00715 的测试数据上,聚类给了我 0.20817 分(满分 1 分)。Eps 是两个样本之间的最大距离,其中一个样本被视为与另一个样本相邻。

考虑到分数,我们可以得出结论,在这种简单的形式下,螺旋聚类确实不是那么准确。至少它作为一个基线,剧透警报,表现最好的方法实现起来有点棘手。聚类仍然在许多算法中使用,一些算法达到 0.8 分以上。

挑战亚军

Kaggle 用户 outrunner 将其解决方案基于人工神经网络。该模型输出具有 1 和 0 的邻接矩阵,1 表示命中在同一轨道上,0 表示它们不在同一轨道上。模型的规模太大了(N ~ 100k ),必须分成更小的单元。它们将一对两次击中作为输入,并输出它们的关系,或者它们在同一轨道上的概率。

Outrunner 神经网络模型

考虑所有的匹配对,并且在每对中考虑 27 个特征。然后在其上训练一个具有 4k-2k-2k-2k-1k 个神经元的 5 隐层多层感知器(MLP)。通常,重建轨迹的方法并不将所有的命中对作为输入,而是仅将相邻的命中对作为输入,这或多或少是传统的连接点。所使用的特征包括击中方向的单位向量,并且使用轨迹是线性或螺旋形状的假设,可以减少假阳性的数量。因为如上所述,当所有可能的对都被使用时,不属于相同轨道的对占优势是不足为奇的。

为了重建轨迹,outrunner 从初始命中开始,并从具有最高预测分数的对中形成种子。添加的第三个匹配项是将两个匹配项放在一起时最大化概率总和的匹配项。它还会接受检查,以查看它是否符合从原点穿过种子对的圆。重复该过程,直到没有进一步的命中符合该轨迹。此后,以相同的方式创建导致新轨道的新的初始命中,直到数据中没有剩余命中。

最后一步是解决轨道之间的不一致,因为它们中的许多包括相同的命中。单个音轨的质量由唯一分配给它的点击量来量化。这一措施是用来排序重叠的轨道,并以最佳方式合并它们,如下所示。

示例轨迹重建

这种深度学习方法在 Kaggle 比赛中获得了第二名,得分为 0.90302。关于亚军的进一步阅读:

[## 冠军访谈|粒子追踪挑战赛亚军,周佩莲

怎样才能接近顶峰?见见周佩莲,我们最近的多轨道粒子赛的亚军得主…

medium.com](https://medium.com/kaggle-blog/winner-interview-particle-tracking-challenge-first-runner-up-pei-lien-chou-41247be42dbf)

获胜的选手

获胜的贡献来自得分为 0.92182 的团队顶级夸克。在机器学习方面,他们的解决方案有一些逻辑回归,用于修剪掉出现的多余轨迹,但除此之外,它是基于统计和 3D 几何的经典数学建模。它还包括磁场作为探测器中 z 位置的函数的原始模型。有趣的是,他们使用了很少的训练事件,大多数模型拟合只使用了一个事件[2]。

算法

  1. **种子生成:**算法从选择有希望的命中对开始。大多数轨迹被探测器最内部的 50 对相邻层覆盖,因此起始点对的候选,或种子,都是这些层上的匹配对。通过使用不同参数的逻辑回归剪枝,减少了候选的数量,最明显的是如果从这两个点外推直线,离原点有多远,其次是给出粒子方向的击中角度。
  2. **扩展到三元组:**通过将现有点之间的线扩展到相邻层并将 10 个最接近的点存储为候选点,将第三个点添加到轨迹中。再次使用逻辑回归修剪,拒绝坏的三元组。
  3. **轨迹跟踪:**一个螺旋被安装到三联体并延伸到其他层。最接近它的点击被添加到轨道。
  4. **轨迹整合:**存在重叠模块,导致测量点未被考虑在内,或者换句话说,探测器中每层的多次命中。如果这些命中比阈值更接近,则它们被添加到轨迹中。
  5. **音轨歧义解决:**到目前为止,每个音轨都被认为是独立的,这导致了不同音轨之间在命中方面的大量重叠。使用基于训练数据的评分标准来选择最佳轨迹。然后,从所有其他冲突路径中移除包含在该路径中的所有命中,这是反复进行的,直到没有冲突剩余。

获胜算法:1。配对查找,2。延伸到三连音,3。添加来自重叠模块和 4 的命中。最终音轨歧义消除。[3]

结论

根据竞赛出版物[3],无法与粒子跟踪的最新技术水平进行直接比较,但我们知道当前的带电粒子跟踪算法基于三个阶段:播种、轨迹跟踪和轨迹选择,许多顶级解决方案也使用这三个阶段。共有 651 个团队参加了竞赛,并由此发明了许多新颖的解决方案。

我已经介绍了一种对数据应用聚类的简单方法,还有更复杂、更精确的解决方案,使用同样的技术,速度相当快。获胜的算法也是如此,它使用高度优化的数据结构,很少使用机器学习,而神经网络的解决方案的运行时间根据早先链接的 Kaggle 采访是“一个天文数字”。我读到了一个很有希望的评论,它来自冠军和亚军,是关于合并他们两个成功的技术的:“我只能想象使用你的接近最佳的配对得分和我的曲目扩展/选择的解决方案会得分有多高”。所有这些不同的方法无疑给了 CERN 的科学家一些思考的素材。

[2]: J. Wind,离群密度估计的快速可扩展跟踪,2018,https://github . com/top-quarks/top-quarks/blob/master/top-quarks _ documentation . pdf

[3]: S .阿姆鲁什等人。al,跟踪机器学习挑战:准确性阶段,关于机器学习挑战的 Springer 系列,第 231-264 页,2019 年

新年烟花造成的颗粒物污染

原文:https://towardsdatascience.com/particulate-matter-pollution-by-new-years-fireworks-5baad6efd540?source=collection_archive---------26-----------------------

PM10 的视频

照片由 米盖尔·阿科斯塔 发自 派克斯

每年新年,成吨的烟花被燃放到空中。众所周知,烟花既不利于环境,也不利于人们的健康。

一份关于荷兰新年烟花负面影响的清晰科学报告呈现在《自然》杂志的一篇文章中,你可以在这里找到: Greven,F.E .,Vonk,J.M .,Fischer,P. 荷兰新年烟花期间的空气污染和每日死亡率。 Sci Rep **9,**5735(2019)doi:10.1038/s 41598–019–42080–6

我想,在新年前后的几天里,将荷兰及其周边地区的颗粒物(PM10)污染可视化可能会很有趣。

在之前的三篇文章中,我概述了我们如何利用公民科学和开放数据来做到这一点:

  • 空气质量测量
  • 看不见的微粒云穿越欧洲
  • 迷人的颗粒物天气

本视频显示了 PM10 污染的结果,时间跨度为 2019 年 12 月 30 日 00:00 至 2020 年 1 月 3 日 11:30。您可以随时暂停视频以查看特定时刻的细节。

不幸的是,Luftdaten.info 网站不像以前那样稳定,由于服务器错误,相当多的拍摄图像不得不被拒绝。这也导致了 12 月 31 日 20:30 和 1 月 1 日 06:00 之间的间隔。然而,PM10 浓度如何在新年前后达到峰值是相当清楚的。

如果我们检查单个传感器的数据,我们也可以看到这一点。午夜前后的峰值非常明显,水平高得令人难以置信!(一个传感器是从乌得勒支市随机选取的,另一个是从鹿特丹市随机选取的。)

相比之下,我自己的传感器,是在比利时的一个地区,禁止烟火,显示在同一时间范围内如下。水平低得多,午夜没有明显的高峰。

1 月 1 日 07:00 左右出现一个高峰,可能是由于 PM10 从其他地区(如荷兰)移入。

天气不好:浓雾和低云,无风,因此污染滞留在低层大气中。

如果烟火在今天被发明,它将永远不会被合法化;它将无法通过安全、环境和健康监管。

将参数传递给 Pytest 中的 Selenium 测试函数

原文:https://towardsdatascience.com/pass-arguments-to-selenium-test-functions-in-pytest-b6c76a320ecd?source=collection_archive---------25-----------------------

从命令行传递用户名和密码进行 Selenium 测试

照片由 NeONBRAND 在 Unsplash 上拍摄

测试硒的功能并不容易。尤其是当我们必须传递参数时,比如用户名和密码。我解决这些问题有些困难。所以我写了这篇文章,希望能节省你的时间。

使用 pytest fixture 传递参数

下面是一个简单的例子来说明如何传递参数。首先,我们需要编写一个conftest.py文件来允许 pytest 在执行命令行时接受参数。延伸阅读:conftest . py 文件有什么用?

测试结果:

好的,输出看起来没问题。我们重写了play.py并在下面展示了两个硒的例子。

一个简单的硒的例子

我们添加硒:

测试结果:

一个复杂的硒的例子

我们在向 TestCase 类传递参数时会出错(原因在失败尝试部分),所以我使用一个test_ftse_links()函数来测试ftse_links()中的所有函数。

测试结果:

我们在conftest.py中使用了pytest.skip()。如果我们没有传递参数,相关的测试将被跳过。

失败的尝试

以下是一些失败的尝试。如果你知道为什么和如何解决它们,请留下评论,我会更新帖子。

无法将 pytest fixture 传递给 TestCase 类

下面是一些错误案例,我试图将参数传递给 TestCase 类,但失败了。

错误案例 1:

测试结果:

错误情况 2:

测试结果:

sys.argv不支持 pytest

使用 Python 运行这个文件没有错误。

但是使用 Pytest 会导致一个问题。

测试结果:

查看我的其他帖子上 一个分类查看
GitHub:
荆棘徐 领英: 徐亮 博客:

参考

  • pytest 注释行:https://docs . py test . org/en/latest/example/simple . html # pass-different-values-to-a-test-function-depending-on-command-line-options
  • py test skip:https://docs . py test . org/en/latest/example/simple . html # control-skip-of-tests-by-command-line-option
  • pytest 命令行:https://stack overflow . com/questions/40880259/how-to-pass-arguments-in-pytest-by-command-line/42145604
  • conf test . py:https://stack overflow . com/questions/34466027/in-py test-what-the-use-of-conf test-py-files

通过 DA-100 微软考试—我的经历

原文:https://towardsdatascience.com/passing-da-100-microsoft-exam-my-experience-6a911b41ec79?source=collection_archive---------4-----------------------

打算考 DA-100,成为微软认证数据分析师?阅读我关于如何成功完成考试的经验

照片由来自佩克斯的罗德里戈拍摄

自从我昨天晚上宣布我已经成功完成了用微软 Power BI 分析数据的 DA-100 考试,我在 LinkedIn 和 Twitter 上收到了大量关于考试准备、考试本身、哪些主题最重要等的消息。

因此,我决定在一篇文章中分享我的全部经验,希望可以帮助其他准备成为数据分析师认证的人。我真诚地希望我不会用这段文字打破任何 NDA,所以如果你期望看到一些问题,答案,描述等。请停止阅读,因为我不会在这里或其他任何地方分享…

什么是 DA-100?

从今年开始(或者甚至可能在去年年底),微软宣布他们将改变认证策略。而不是针对特定工具(例如 SQL Server、Power BI 等)进行认证。),认证现在基于特定的 角色 (比如数据分析师、数据工程师、数据科学家、开发人员等等)。

这意味着旧的认证和考试将被取消(最初计划在 2020 年年中取消,现在在撰写本文时截止到 2021 年 1 月 31 日),所以如果你打算参加“旧的”考试,赶快:)

DA-100 是使用 Power BI 分析和可视化数据的现有 70–778 的“合法”继任者。如果你简单看一下这两个考试的课程,我会说它们有 80%的重叠,这意味着如果你已经准备了 70-778,你可能很容易转换到 DA-100。

但是,由于 Power BI 变化如此之快,DA-100 中包含了许多新奇的新功能,尤其是与 AI 相关的功能。然而,如果你还不熟悉这些话题,不要害怕——它们只占考试的一小部分。

准备考试

老实说,我没有为考试做任何特别的准备。因为我每天都在使用 Power BI,所以我认为实践经验在我的案例中扮演了重要的角色。然而,我最担心的是,我主要使用 Power BI Desktop for Report Server(Pb IRS ),在企业环境中使用 Power BI 服务的经验非常有限。

也就是说,我对“部署和维护可交付成果”的技能感到很吃力。因此,我必须找到一种替代的方法来获取这一重要部分的知识。

皮查拜在 Pexels.com 拍摄的照片

我忘了说,我已经在测试阶段参加了考试,所以没有官方的学习指南,但是当考试开始时,我注意到微软为考试的每个部分发布了学习路径!

这是一个非常好的消息,因为你可以找到每一个主题的细节。我使用 Microsoft Learn 来提高我对 Power BI 服务的了解,我不得不承认他们确实做得很好。因此,如果你想免费准备,只需进入微软学习网站,开始浏览所有主题。

另一个很好的资源是来自 BI Elite 的 Parker Stevens 的在线课程。这门课程不是免费的,但是你得到的东西也不贵。它将带您浏览准备列表中列出的每一个要点。我只看了几个视频,但是从我从其他人那里听到的和知道 Parker Stevens 是一个真正的 Power BI 专家,我相信这个课程也是值得考虑的。

然而,老实说,对于打算成功通过考试的人来说,使用 Power BI 的实际操作经验是最大的优势。我不想让刚接触 Power BI 或以前没有使用过它的人气馁,只是准备好走更艰难的路…

三,二,一…考试

我知道你们大多数人对这一部分感兴趣,所以对之前的长故事没有什么不好的感觉:)…我需要为最有趣的部分打下基础。

考试本身 180 分钟,不急不躁的完成一切绰绰有余。所以,这篇博文的第一个要点是:

不要慌,不要急——真的有足够的时间来彻底思考问题和答案,并在以后回顾一切

考试由多项选择题和案例分析组成。我的建议是:

在进行案例研究时,请保持高度专注,因为有些具体要求需要仔细研究

最后,我的感觉是,主题的分布或多或少是均匀的,但如果我需要选择看起来比其他主题更有代表性的主题,这将是我的列表:

幂查询(尤其是幂查询转换)

特定可视化类型的使用

数据建模

你们很多人问我 DAX 和 M 在考试中占多少。老实说,不多,只有一些非常基本的东西,在任何情况下,这都应该是任何有抱负的数据分析师(和权力 BI-er)的默认技能集的一部分。

后果

一旦你完成考试,你应该立即得到你的结果。我不得不等到考试从测试版变为正式版,但这是值得等待的:)

如果你成功地通过了考试(我相信每个正在阅读这篇文章的人都会这样做),你就获得了 MCSA 认证(微软认证:数据分析师助理),从你参加考试之日起两年内有效。

而不是一个结论,我的消息给任何计划参加这个考试的人: 继续学习和练习 ,如果你被卡住了,答案到处都是(Power BI 社区真的很棒)。如果你付出足够的努力和奉献,我相信最终你会获得认证的。

如果您有任何其他问题或考虑,请随时在下面留下评论…

成为会员,阅读媒体上的每一个故事!

订阅这里获取更多有见地的数据文章!

通过编码面试

原文:https://towardsdatascience.com/passing-the-coding-interview-2527bfb6606d?source=collection_archive---------10-----------------------

来自另一方的非传统建议

对于那些更喜欢视觉体验的人来说…

在我的职业生涯中,我采访过几十个人。这篇短文旨在给你一些关于如何通过求职面试的非传统建议。

对于那些不知道的人来说,软件开发人员或工程师的面试过程分为两个部分:你的个人面试——找出你的个性类型,确保你适合团队;第二次面试——解决问题的面试——你会得到一些你需要解决的技术问题。

要得到一份工作,你需要在两次面试中都得 a。无论你是多么有天赋的程序员,如果你是一个糟糕的人,或者侮辱了你的面试官,或者传达了你很难共事的信息,许多公司都不会雇佣你。相比之下,如果你是一个有着金色液体般魅力的人,但没有技术才能,那么这也是一个失败。理想情况下,你希望降落在中间的某个地方。那么,从哪里开始,如何解决这个问题呢?

提示 1:向面试官提问,并积极倾听他们的回答。

人们喜欢谈论自己。面试的时候问问题来解开这个行为特质。同样,用你的问题来帮助你确定这个角色是否是你想要的。也许你正在寻找超过 250,000 的薪水,但是每晚还要睡 5 个小时,并且随时待命。或者,也许你正在寻找工作生活的平衡,由于其他重要的义务,想要有一个可预测的例行公事。两个都好。两者都可以由非常不同的公司或者非常不同的团队来解决。

以我个人的经验来看,学习如何完成一项特定的任务,以及学习关键的解决问题的技巧来赢得编码面试,这些都可以在网上找到,并且大量存在。事实上,像 OutCo 这样的公司教软件工程师如何具体解决这些类型的算法。这里也有一些很棒的资源,包括 Gayle Laackman McDowell 的著名著作《破解编码面试》。

在我个人看来,我认为技能是可以学习的。一般来说,只要准备充分、思路清晰、注意力集中,大多数人都能学会一项新技能。人们通常很难在一夜之间彻底改变自己的性格,或者需要更深入的内在工作。

我记得我面试过两个 ML 工程师职位的人:他们都毕业于优秀的学校,有着非常相似的简历。但是其中一个真的很不愉快,挑战我们说的一切。另一个很好奇,也以礼貌的方式向我们挑战,并且可以进行除了闲聊之外的谈话。

所以这份工作给了第二个人,因为我之前工作的那家公司招聘人不仅仅是看他的能力,还看他是否能和他将被分配到的团队很好地合作。所以…你永远不知道。那么你如何面对或准备面试的这一部分呢?

你为什么不多告诉我一些呢?

技巧 2:收集情报

揭开公司简介,做一些研究,找出他们在寻找什么。找到将要面试你的特定人的信息会更好。

不幸的是,许多想找一份软件开发人员/工程师工作的人根本没有合适的资格。你可以读完麻省理工学院、UIUC、卡内基梅隆大学或哈佛大学,但如果你不知道什么时候使用 Dijkstra 算法,或者如何实现它的变体,那你就太不幸了。

你也一样,**不需要去名牌学校学习如何成为一名伟大的软件工程师。**我遇到过一些人一边学习如何编码,一边为他们的生存工作提供食物。我见过帕洛阿尔托的家庭主妇,她们有三个孩子,决定要改变职业。我甚至遇到过甚至没有上过传统学院或四年制大学的人,他们中的一些人是我所知道的最真实和最优秀的工程师和工程经理。

那么,在编码面试中,我们实际上在寻找什么呢?嗯,这导致…

提示 3:规划你的思维过程

在深入研究代码之前,考虑一下写出或绘制代码。现在我知道,我知道,你们中的一些人会说,“不,我想展示我可以弄脏我的脚!”好吧,让我告诉你。如果你只是花一点时间,真正通读这个问题,你可能会抓住或错过一个关键的特点,你看了,因为我们的人类倾向于启发式和精神捷径。

实际上,如果你正在使用类似的代码板,那么写下一些注释或框架代码来概述你的思考过程,这样你的面试官就知道你是如何思考的。如果你似乎偏离了方向,这也有助于一位仁慈的面试官轻轻地引导你走向正确的方向。

如果我不知道你想去哪里,我就帮不了你。

换句话说,在你开始钻研代码之前,一定要规划好你的思维过程。至少,在开始编写代码之前,先尝试分解问题,并与我们分享您的一般方法。

这就引出了我们最关键的一点。

如果我不知道你是怎么想的,那我就收不到信号

技巧 4:交流你的想法

当然,在一个理想的环境中,我们希望看到你写出一个可行的,最好是时间优化的解决方案。然而,情况通常并不理想,你可能无法及时找到可行的解决方案。你会认为这是失败吗?也许吧。

但是在我们这边,这并不总是失败的。其实更重要的是你如何沟通你的想法。心灵感应还没有普及到每个人,所以一个普通的面试官不能在解决问题的时候凭直觉准确地知道你在想什么。

现在,我不是让你写完每一行后都要讲话。那实际上会有点令人不安…我不希望你变成一个喋喋不休的凯西,然后说得太多以至于你永远也解决不了问题。

然而,有时交流你的意图和你的思考过程会给我们这些招聘人员提供一个关于你如何思考的信号。它也能给你提供一个信号。特别是,神经科学研究表明,当我们将次发声过程(心理交谈)转变为外化发声(说话交谈)时,人们实际上更快地达成解决方案。

著名的橡皮鸭,我最好的朋友!

另一种很多人使用的生产力或领导方法叫做橡皮鸭。换句话说,说话。使用口语作为工具来传达你在解决问题的过程中所处的位置。如果你要考虑一些事情,给我们一个信号,让我们知道你会探索这样的解决方案。这个实用的建议看起来似乎很简单,但是你会惊讶地发现,我经常听到有人在压力下谈论他们的方法或思维过程时感到很不舒服。这就是与朋友(或陌生人)的模拟面试真正派上用场的地方。

记住,如果你知道解决方案,但不能解释你的逻辑——对你来说面试就结束了。招聘人员想看看你的大脑是如何工作的。你可能无法得出一个完美的解决方案,但如果你能解释你的解决方案,并编写出一个 80%正确的解决方案,你仍可能“通过”,这取决于公司和面试官的宽容程度。

记住伙计们。作为一名软件工程师,你被雇佣来思考软件。虽然最终的可交付成果是工作代码,但我们也需要找到一种方法来评估您的思维方式。就像我开始说的,如果你不说话,我就猜不到你在想什么。

另外,我建议每天练习算法。在我的另一个视频中,我提到了做代码形。这是一种方法!给自己一些时间压力,跳上像 HackerRank 这样的网站,解决他们的一个算法。

你知道他们有时会说,一天一个苹果,医生远离我?嗯,有时候我想说,一天一个形可以让你远离困惑!

通过 7 个简单步骤完成数据科学带回家项目

原文:https://towardsdatascience.com/passing-the-data-science-take-home-project-in-7-easy-steps-d708d6e13c8d?source=collection_archive---------23-----------------------

易于遵循的指南。

尼克·舒利亚欣在 Unsplash 上的照片

祝贺你,你通过了最初的面试,进入了数据科学项目!招聘人员在这一点上给了你一套极其模糊的指示。你可能会发现自己在凌晨 2 点盯着电脑,就像上图中的那个人。

这个项目应该只需要几个小时就可以完成,但是我们会给你一周的时间交上来

面试过程的这一部分不应该这么难。我将帮助您通过数据挑战,并成功进入面试流程的下一部分。

请记住,他们不希望你建立最成功的模型,他们有大量的资源,花费几个月的时间为手头的问题创建可行的模型。他们更关心你如何处理一个复杂的问题,你的代码、注释、解释和组织。

以下是数据科学项目中要遵循的 7 个步骤。

对您的项目有帮助的其他有用信息。

[## 了解你的观众。如何展示你的数据科学项目!

如何定义和调用将您的冗长代码隐藏在别处的函数。

towardsdatascience.com](/know-your-audience-how-to-present-your-data-science-project-96a3c5d4d475)

1。简介

S 挞着干嘛。为什么这个项目很重要,谁会从定义良好的模型和解决方案中受益?公司为什么会在意?

抓住机会展示您识别数据挑战的业务需求的能力。通常公司会给你一个和他们业务相关的题目。作为一名数据科学家,这是您将项目绑定到一个有意义的故事的机会。

示例(欺诈案例模型):

作为信用卡提供商,重要的是要有防范措施来打击欺诈。对于 2019 财年,欺诈交易占 150 万美元[从数据中收集]。这不仅会造成金钱损失,还会影响客户对公司保护他们的信任…

2.探索性数据分析

照片由 Isaac Smith 在 Unsplash 上拍摄

探索探索探索!

请记住,你的大量时间(在工作中)将用于争论数据。使用此部分创建一些图表并深入了解数据。

需要考虑的一些图表:

  • 直方图(欺诈-非欺诈交易)
  • 相关热图
  • 一段时间内的平均交易。

永远记得探索缺失的数据。丢失信息是这个过程的一部分,能够识别它是至关重要的。要寻找的东西:

  • NA,Nan,空
  • 空字符串" "
  • “缺失”或“空白”这个词

现在不是创造新功能的时候。相反,使用这一部分来奠定基础。

您应该花时间确定您将如何处理丢失的数据,要么丢弃它们(在丢弃它们时确保检查目标变量分布),要么输入值(平均值、中值、众数)。

3。基线—简单模型

我们如何确定我们的模型性能是成功的?成功是一个相对的术语。与当前流程相比,模型是成功的。例如,你可以建立一个准确率为 95% (65%)的模型,但是如果当前的方法准确率为 97% (55%),你就没有增加价值。

这一部分将用于创建基线模型。这个模型将是基础,以便可以比较其他复杂的模型。因为这是你对这个问题的“第一次尝试”,它不需要过于复杂或微调。您可以在本节开始时声明,您将把数据扔给一个模型(简单模型),看看它做得有多好。

解释,解释,解释!

当选择基线模型(或任何模型)时,您必须解释为什么选择建模技术。没有正确的答案,但是有一个答案会说明你在建模之前就考虑到了这个问题。

一个可以接受的答案是:

“这个模型既简单又直观,在过渡到更复杂的模型之前,它将是一个很好的基线。在向业务涉众解释模型时,简单性具有优势。”

最后,展示成功指标(RMSE、精确度/召回率、混淆矩阵、ROC 曲线)并(再次)解释它。如果模型表现不佳,不要惊慌。

4。特征工程

现在,您可以开始根据现有数据创建一些新要素。提醒一下,他们不是在寻找一些抽象的赢得世界的特性。创建一些你认为重要的特性,并解释为什么你认为它们会有助于提高性能。其中一些特性将源自 EDA 部分,在这里您可以深入了解数据集。

继续我们的欺诈示例,这里有两个特征:

  • Over_Avg :当前交易>是否为平均交易?
  • Credit_Util: 卡内余额/信用额度

5.超参数调整和复杂模型

至此,您已经为业务问题奠定了基础。现在您正处于十字路口,您可以通过调整超参数和实现新功能来扩充基线模型,或者运行不同的模型(例如,从逻辑回归改为随机森林)。无论你做出哪个选择,一定要解释背后的原因。

如果时间允许,我倾向于两样都做。

由马库斯·温克勒在 Unsplash 上拍摄

再次强调成功指标并解释结果。希望模型比基线表现得更好。

6.后续步骤

差不多了,再坚持几个小时吧!你可能很想回到第 5 步,对模型进行更多的调整,以获得“完美的”结果,但是在这个任务中没有所谓的完美。相反,如果你在这项任务上花了更多的时间,你应该概述下一步你会做什么。

需要考虑的写作内容:

  • 为什么你的模型失败了——有证据表明过度拟合吗?
  • 额外的超参数调整-使用交叉验证来搜索网格。
  • 您希望开发的其他功能
  • 平衡数据集,以便更好地表示每个类

当您概述下一步时,也包括一个您认为它将如何提高模型性能的简要描述。

7.结论

Ian Stauffer 在 Unsplash 上拍摄的照片

请记住,您正在讲述一个数据故事。重申为什么这个项目很重要,以及你想解决的问题。总结您在探索部分收集的见解以及模型的表现。最后,解释你的模型将如何解决这个问题。

在你发出那个项目之前,一定要做一些最后的任务。校对你的演示文稿,确保在整个代码中都有注释,并且组织得很好。

祝好运!

感谢您的阅读,感谢您的评论和反馈。你可以在 LinkedIn 上找到我!

走过 AI 转型的拐点

原文:https://towardsdatascience.com/passing-the-turning-point-of-ai-transformation-4855bc9742a1?source=collection_archive---------52-----------------------

您将如何受益于 Milvus ,一个面向数据科学家的开源项目

谈到开源人工智能项目,人们会想到 Google TensorFlow、PyTorch 等模型框架项目。由于模型框架是训练人工智能模型的关键部分,这些项目通常受到最多的关注。但是人工智能(AI)不是一种技术。人工智能是一个复杂的技术领域,涉及几个子领域和许多不同的组成部分。

Milvus是一个开源项目,为开源 AI 生态系统提供数据服务功能。

开源 AI 项目在不同子区域的景观 ( 作者图片)

AI 转型的转折点

一般来说,技术升级的转折点是技术升级的回报远远超出成本的点。当它应用于人工智能转换时,它将涉及包含模型(算法)、模型推理和数据服务的基本因素。

当谈到模型时,我们需要问自己关于利用人工智能技术的期望。如果我们想用人工智能技术击败并取代人类工人,例如,用人工智能驱动的对话机器人取代所有的客户支持专家。那么对人工智能模型的需求将会非常高,甚至在短期内都无法实现。

如果我们希望将我们的客户支持专家从繁琐的日常事务中解脱出来,这意味着我们打算利用人工智能技术作为放大器来提高人类的生产力和能力,那么今天的模型在许多场景中已经足够好了。

听起来很鼓舞人心。然而,关于模型的一个激烈的争论是,尽管一些模型是公开的,但是最好的模型(最先进的模型,SOTA)不是。那些可以雇佣拥有这些 SOTA 模型的人工智能科学家的公司。如果我只使用公共型号,我会失去竞争优势吗?

人们对此感到困惑,因为他们认为效率更高的模型会带来更高的商业价值。然而,这可能是错误的。在大多数情况下,模型有效性和商业价值之间的关系既不是线性的,也不是单调递增的。该函数的图形应该如下所示。

模型有效性和商业价值的关系(图片作者

它是一个分段函数。第一阶段,模型在应用场景中实用之前,没有商业价值。在第二阶段,虽然理论上更好的模型应该具有更好的性能(响应时间、有效性等)。),这在现实世界中可能并不明显。让我们看看下面的情况。

在医生能够确认患者是否患有肺部感染之前,医生需要拍摄可疑患者肺部的 CT 图像。它会产生大约 300 张 CT 图像。一个有经验的医生必须花 5-15 分钟来研究这数百张 CT 图像。正常情况下,如果一个医生只处理少数病人,这不会是一个问题。然而,在像新冠肺炎这样的极端情况下,医生会被激增的病人压垮。

好消息是数据科学家已经尝试通过计算机视觉技术来帮助医生。他们训练模型可以处理数百张 CT 图像,并在几秒钟内提供诊断建议。因此,医生只需要花 1 分钟来查看模型生成的结果。

因此,在应用机器学习技术之前,平均需要 10 分钟来查看一次 CT 扫描产生的结果,现在只需要大约 1 分钟。生产率提高了近 90%。

如果我们有一个更快的模型,只需要 3 秒钟就可以生成结果,会怎么样?从 1 分 5 秒到 1 分 3 秒,看起来并不吸引人。

如果我们有一个更有效的模型,可以将准确率从 80%提高到 90%,会怎么样?医生可以减少检查结果吗?答案是否定的,因为**,**虽然这个模型只有十分之一是错误的,但我们无法知道哪一个是错误的。因此,最终审核者必须检查所有结果。因此,它不会节省更多的诊断时间。

此外,为了降低模型推理服务的成本,我们有时宁愿牺牲模型的有效性。这里有一个来自我们用户的真实例子,他们是一个拥有 5500 万张商标图片的商业智能平台。该公司希望提供一项服务,允许用户搜索这些商标的所有者。用户通过上传商标图像作为输入查询来执行搜索,而不是给出关键词。

背后的技术是计算机视觉,例如,VGG 模型。如果公司在后端服务器上运行模型推理,他们必须分配和保留数据中心的硬件资源。另一种选择是部署一个较小的模型,以便公司可以将模型推理放在边缘设备上(大多数情况下是智能手机)。肯定会砍掉 GPU 这种昂贵的模型推理硬件的成本。这是 SOTA 模式不可能在所有情况下都具有竞争力的另一个例子。

我们已经处于 AI 转型的转折点。接下来的问题是,我们如何度过这个转折点,并采用人工智能技术来增强我们的业务。

可用的模型是先决条件。然而,如果我们只有模型,我们就不能轻松地开发一个人工智能程序。与传统应用程序一样,数据服务始终是一个关键部分。我们可以看到它正在成为当今人工智能应用中的一个重要组成部分。这就是为什么我们发起了开源项目-Milvus,以加速人工智能的采用。

人工智能采用的数据挑战

我们试图通过人工智能技术处理的大部分数据都是非结构化的。我们期望 Milvus 项目为非结构化数据服务提供一个坚实的基础。

人们通常将数据分为三种类型,结构化数据、半结构化数据和非结构化数据。结构化数据包括数字、日期、字符串等。半结构化数据通常包括特定格式的文本信息,例如各种计算机系统日志。非结构化数据包括图片、视频、语音、自然语言和任何其他无法由计算机直接处理的数据。

据估计,非结构化数据至少占整个数字数据世界的 80%。例如,您可能每天与家人、朋友或同事发送和接收几千字节的文本消息。但即使你只在移动设备上拍了一张照片,比如说是 1200 万像素摄像头的 iPhone 11,也要好几兆。而如果用 720p 分辨率拍摄视频呢?

人们开发了关系数据库、大数据技术等技术来高效处理结构化数据。半结构化数据可以由基于文本的搜索引擎处理,如 Lucene、Solr、Elastic Search 等。然而,对于所有数据中的大块非结构化数据,人们过去没有有效的分析方法。直到近年来深度学习技术的兴起,非结构化数据处理的发展一直是不可想象的。

非结构化数据服务

嵌入是一种深度学习术语,指的是通过模型将非结构化数据转换为特征向量。由于特征向量是一个数值数组,所以很容易被计算机处理。因此,对非结构化数据的分析可以转化为向量计算。

一个最常见的论点是特征向量似乎是非结构化数据处理的中间结果。有必要建立一个通用的向量相似性搜索引擎吗?它应该包含在模型中吗?

从我的角度来看,特征向量不仅仅是中间结果。它是深度学习场景下非结构化数据的知识表示。这也被称为特征学习。

另一种说法是**、**既然特征向量也包含数值,为什么不在现有的数据处理平台如数据库或计算框架如 Spark 上进行向量计算。

准确地说,向量由一系列数字组成。它导致了向量计算和数值运算之间的两个显著差异。

第一,向量和数最频繁的运算不一样。对于数字来说,加、减、乘、除是最常见的运算。但是对于向量来说,最常见的要求是计算相似度。你看,这里我给出的是欧几里德距离的计算公式,向量的计算远高于普通的数值计算。

其次,数据的索引组织不同。在两个数字之间,我们可以相互比较数值。因此,我们可以根据类似 B 树的算法创建数字索引。但是在两个向量之间,我们无法进行比较。我们只能计算它们之间的相似度。因此,向量索引通常基于类似近似最近邻神经网络算法的算法。

一个空间分割算法(图片作者

由于这些显著的差异,我们发现传统的数据库和大数据技术很难满足向量分析的要求。他们支持的算法和关注的场景都不一样。

我们没有在 Milvus 项目中重新发明轮子。

Milvus 项目在典型人工智能应用中的位置(作者的图片)

找出使用案例

用例链接:

  1. 米尔维斯× VGG:构建基于内容的图像检索系统
  2. 由 Milvus 支持的更智能的房屋搜索和推荐
  3. 加速新药研发

加入开源社区

Milvus 项目是由 LF AI 基金会主办的孵化项目。

请随时 加入 Milvus 项目 的社区。如果你对 Milvus 项目感兴趣,想在此基础上构建人工智能应用,或者想参与项目开发。

如果您想了解有关该项目的更多细节,请关注出版物 非结构化数据服务

关于作者

我是 顾俊 ,一名数据库工程师,也是 Milvus 开源社区的热心组织者之一。

我现在是 LF AI 基金会技术顾问委员会(TAC)的成员。然而,我最长的工作经历是在金融技术领域。我在摩根士丹利的企业基础设施部工作了 8 年。

拼凑——下一代 ggplots

原文:https://towardsdatascience.com/patchwork-the-next-generation-of-ggplots-1fcad5d2ba8a?source=collection_archive---------60-----------------------

进一步扩展 ggplot2 的多功能性..

尼古拉斯·彼尔托在 Unsplash 上的照片

对于 R 中的数据可视化,ggplot2已经成为生成出色的、高质量的发布图的首选包。它的分层方法使我们能够从简单的视觉基础开始,并在每一层中不断添加修饰。即使是默认设置的最基本的绘图,看起来和感觉都比 base R 图形好得多。因此,如果你计划或需要与内部利益相关者或外部客户分享你的分析成果,你的技能组合中必须有 ggplot。是的,有一个学习曲线(自尊技能没有!)但一旦掌握,ggplot2提供了极好的定制可能性,并以引人注目的方式传达您的洞察力。

但是这个帖子本身并不是关于 ggplot 的!相反,它是关于现在可用的令人敬畏的布局功能,超越了通过ggplot2facet_wrap()facet_grid()方法可用的标准网格选项。

当您想要将一组相关的图组合到一个图形中,但是发现一些图看起来比其他的更宽,并且打乱了行和列以及行/列宽度的网格约束时,灵活的布局选项特别有用并且非常缺少。或者更糟的是,到处都有一连串的传说。

输入patchwork

patchwork建立在+的基础上,现在不仅能让我们在ggplot2的基础剧情中增加一层,还能让我们控制支线剧情的位置和大小。所有这些只需要 3 个“操作符”:+()/。让我们来看看吧!

装置

确保您已经安装了ggplot2包。如果你以前没有用过ggplot,请点击 Selva Prabhakaran 的阅读这篇综合教程。

library(ggplot2)
install.packages('patchwork') # first time installation
library('patchwork') # load the library in to your R environment

我们将使用来自ggplot2的德克萨斯房屋txhousing数据集来演示patchwork的能力。让我们快速检查数据集的维度和前几行。

data = ggplot2::txhousing
dim(data)

head(data)

它有 9 列和 8602 个观察值,包含美国德克萨斯州 2000-2015 年各月的城市房屋销售和库存数据信息。您可以在 R 控制台上使用help(txhousing)命令来检查列的详细描述。为了演示的目的,让我们只考虑达拉斯市的数据。

dallas = data[data$city == "Dallas",] # take a subset of data only for Dallas

我们现在将创建一些将在patchwork使用的 gg 图

avg.monthly.sales = dallas %>% group_by(year) %>% summarise(mean = mean(sales))mytheme = theme(panel.background = element_rect(fill = "powderblue")) # set a ggplot theme for repeated use laterp1 = ggplot(avg.monthly.sales, aes(year,mean)) +geom_col(fill = "gold", color = "navyblue") + ylab("Mean Monthly Sales (Nos)") +mytheme + labs(title = "Dallas - 2000 to 2015")p1

avg.monthly.vol = dallas %>% group_by(year) %>% summarise(mean = mean(volume))p2 = ggplot(avg.monthly.vol, aes(year,mean)) +geom_col(fill = "gold", color = "navyblue") + ylab("Mean Monthly volumes in USD") +mytheme + labs(title = "Dallas - 2000 to 2015")p2

dal_2014 = dallas %>% filter(year ==2014)p3 = ggplot(dal_2014, aes(month,listings)) +geom_line(color = "navyblue") + mytheme + scale_x_continuous(breaks = c(seq(1,12,1))) +labs(title = "Dallas 2014: Property Listing Count")p3

avg.monthly.inventory = dallas %>% group_by(year) %>% summarise(mean = mean(inventory))p4 = ggplot(avg.monthly.inventory, aes(year,mean)) +geom_col(fill = "gold", color = "navyblue") + ylab("Mean Inventory (No of months)") +mytheme + labs(title = "Dallas - 2000 to 2015")p4

现在,假设我们希望将两个或更多的图显示为一个图形。像gridExtra这样的扩展可以胜任工作,但是选项仅限于正方形或矩形网格,每个单元格有一个子图。这里是patchwork一击即中的地方,几乎不需要布局代码。看着!!

p1 + p2

就是这样!像加法一样简单..现在对于一些部门来说。

(p1 + p2) /p3

再多堆一些..!

照片由 amirali mirhashemian 在 Unsplash 上拍摄

p1/(p3+p4)/p2

很棒吧?这个包还可以选择将所有相同的支线剧情合并成一个单独的图例和更多的特性。我将发布一篇单独的文章来讨论这个问题。

关于 R 中另一个方便的探索性数据分析(EDA)工具,点击这里看我关于SmartEDA的文章。

感谢您的阅读,并请留下您的意见和反馈。

病人知识蒸馏

原文:https://towardsdatascience.com/patient-knowledge-distillation-88969fffb4ba?source=collection_archive---------36-----------------------

让大型语言模型变得更小,以便在日常设备上使用。

邦内瓦尔·塞巴斯蒂安在 Unsplash 上拍摄的照片

随着深度学习的出现,更新更复杂的模型正在不断提高各种任务的性能。然而,这种改进是以计算和存储资源为代价的。这些模型中的大多数都有数百万或数十亿个参数,需要花费数天时间用具有几个 GPU 的极其强大的机器来训练。例如,Krizhevsky 等人的工作在 2012 年的 ImageNet 挑战赛中使用包含 6000 万个参数的网络取得了突破性的结果,该网络具有五个卷积层和三个全连接层。

这带来了一个新的挑战:将这些模型放在手机等设备上,这些设备的内存和计算资源通常比训练模型的服务器少得多。为了解决这个问题,研究人员开始探索模型压缩的想法,这种想法专注于在不损失太多准确性的情况下减少模型大小。为此设计了几种通用技术,包括量化(减少存储每个权重所需的位数)、参数共享(这减少了模型所需的总参数)和知识提取(创建一个新的“学生”模型,其层数较少,但精度与原始“教师”模型相似)。

在这项工作中,微软 Dynamics 365 AI 研究团队主要专注于压缩像 GPT 和伯特这样的艺术语言模型,这些模型虽然庞大,但构成了大多数 NLP 模型的基础。例如,BERT-base 有 1.09 亿个参数,BERT-large 有大约 3.3 亿个参数。为了使这些模型更小,他们提出了一种新的知识蒸馏(KD)方法来压缩模型,从而节省运行时间和内存,而不会损失太多的准确性。

当一个语言模型被传统的知识发现技术压缩时,当应用于下游任务如句子分类时,它会失去很多准确性。这是因为以前的 KD 方法集中于教导学生模型教师预测的最终概率 logit,而没有考虑任何隐藏层值。这类似于现实生活中的一个场景,一个孩子知道一个问题的最终答案是什么,但不知道他们是如何得到这个答案的,当面对一个稍微不同的问题时,孩子更有可能犯错误。使用传统的 KD 方法学习的学生模型也是如此。基于这一假设,本文提出了一个损失函数,该函数不仅试图将学生模型的最终概率与教师模型的最终概率相匹配,而且试图将它们的隐藏表示相匹配,从而使学生模型的泛化能力更强。这种模式被称为“病人知识蒸馏”(PKD)。

这项工作特别关注用于句子分类的 BERT 语言模型。在此设置中,模型的预测基于每一层的[CLS]字符(一种捕获上下文句子编码的特殊字符)的特征表示,例如向该特征添加两层完全连接。因此,PKD 提出了一种新的损失函数,使模型能够同时学习每一层[CLS]角色的特征表示:

其中 M 是学生的层数(如 3,6),N 是教师模型的层数(如 12,24),h 是模型中【CLS】隐层的表示,I,j 代表学生-教师,隐层的对应关系如下图所示。例如,当使用 12 层教师模型训练 6 层学生模型时,学生模型可以学习教师模型的每个交替隐藏层(在这种情况下是 2、4、6、8、10)的表示,称为 PKD-跳过,或者它可以学习教师模型的最后几层(在这种情况下是 7、8、9、10、11)的表示,称为 PKD-最后。我们不考虑学习教师模型的最终(第 12)层,而是直接学习最终概率预测,这也包括最终层的隐藏表示。

我们的方法,PKD-斯基普和 PKD-如何学习他们的层的可视化表示。

该团队应用这种技术,使用上述两种方法将 12 层 BERT 基础模型压缩为 6 层和 3 层 BERT 模型。他们发现 PKD-斯基普方法优于 PKD-拉斯特方法,所以所有讨论的结果都使用 PKD-斯基普方法。在 GLUE benchmark 上测试这两个压缩模型表明,PKD 击败了传统的 KD,并且不会导致准确率大幅下降。根据任务的不同,6 层 BERT 比 12 层 BERT 低 0.2%到 3.6%,而 3 层 BERT 低 2.8%-11.9%。这种下降是意料之中的,因为较小模型中的参数明显较少,这使得它们更难捕捉 12 层模型能够捕捉的所有信息。

在 RACE benchmark 上进行测试时,PKD 再次明显优于传统的 KD,6 层模型的准确性仅比 12 层模型低 5%。这种技术的最大好处是加快了预测流水线的速度(6 层快 1.94 倍,3 层快 3.73 倍),并减少了模型所需的存储(6 层少 1.64 倍内存,3 层少 2.4 倍)。因此,通过 PKD,大型语言模型可以变得更小、更快,以便在笔记本电脑和手机等小型设备上使用。

如果你想了解更多关于 PKD 的细节,这里有一个链接到论文,点击这里查看更多出版物和团队的其他工作。

参考文献

  1. 于成,王铎,周磐,张涛,深度神经网络模型压缩与加速综述 (2017),arXiv 预印本 arXiv:1710.09282
  2. A.Krizhevsky,I. Sutskever,G. Hinton,使用深度卷积神经网络的 Imagenet 分类,神经信息处理系统,NeurIPS 2012
  3. 孙思齐,于成,甘哲,,病人进行 BERT 模型压缩,自然语言处理中的经验方法,EMNLP 2019

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/71396.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

jmeter 参数化 csv插件的读取文件 bin目录

问题: ${__P(user.dir,)}${__P(file.separator,)}

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

TowardsDataScience 博客中文翻译 2019(四十一)原文:TowardsDataScience Blog 协议:CC BY-NC-SA 4.0机器学习中的核心秘密。一原文:https://towardsdatascience.com/kernel-secrets-in-machine-learning-2aab4c8a295f?source=collection_archive---------5--------------…

TowardsDataScience-博客中文翻译-2019-四十二-

TowardsDataScience 博客中文翻译 2019(四十二)原文:TowardsDataScience Blog 协议:CC BY-NC-SA 4.0井字游戏的经验教训:实用强化学习技巧原文:https://towardsdatascience.com/lessons-learned-from-tic-tac-toe-practical-reinforcement-learning-tips-5cac654a45a8?so…

.Net PdfiumViewer 打印时无法渲染电子签名问题的解决方法

需要修改源代码或直接反编译动态库修改 PdfPrintDocument.RenderPage 方法,本文仅介绍修改动态库。转载请标明原出处:https://www.cnblogs.com/crpfs/p/18463735 1. 先决条件 本文修改的动态库是从如下的 NuGet 包中获取的:如果使用的是 Visual Studio 中的 NuGet 包管理器获…

现代化 React UI 库:Material-UI 详解!

随着 React 在前端开发中的流行,越来越多的 UI 框架和库开始涌现,以帮助开发者更高效地构建现代化、响应式的用户界面。其中,Material-UI 是基于 Google Material Design 规范设计的一款开源 React UI 库,Github Star高达 94K,凭借其丰富的组件库、灵活的定制化选项以及无…

将html元素保存为图片

初始需求是echarts绘制的图表保存为图片, 后来发现,echarts图标之外,还有一个参数input/button也要放到图片中 于是,技术实现从简单的《echarts导出为图片》 变成了较为复杂的《html元素导出为图片》先放出已经实现的《echarts导出为图片》的代码,// 导出 图片generatePic…

第十期机器学习基础 02注意力机制和Transformer/Bert

一:注意力机制 (一)前提背景 1.人类的选择性视觉注意力 视觉注意力机制是人类视觉所特有的大脑信号处理机制。人类视觉通过快速扫描全局图像,获得需要重点关注的目标区域,也就是一般所说的注意力焦点,而后对这一区域投入更多注意力资源,以获取更多所需要关注目标的细节信…