TowardsDataScience-博客中文翻译-2021-三十八-
TowardsDataScience 博客中文翻译 2021(三十八)
基于远大期望的快速数据质量框架
图片由 your_photo 来自 freepik
在我之前的文章中,我解释了如何使用 Great Expectations (GE)和 Allure Serverless 在数据湖中构建和实现数据质量监控。虽然我描述的过程非常简单明了,但是手动实现需要大量的时间和资源,这就是为什么我提供了一种更快的方法来提高新环境中的数据质量。在本文中,我将讨论前一种方法的限制,并提供规避它们的方法。
这部作品的要点
在整理这个简短的指南时,我的目标是让您能够减少重复的手工工作,并加速和简化诸如创建 AWS 资源、生成和上传必要的配置文件以及编写数据 QA 测试等任务。
为了实现这一点,我们将选择不使用无服务器框架。相反,我们将应用 Terraform 脚本,并使用 Pandas Profiling 来基于分析报告生成数据测试。您所需要做的就是在 config 中设置变量并运行脚本。部署后,使用要检查数据质量的文件运行 Step 函数管道。
请记住,您的输入数据很重要。我们在亚马逊 S3 使用一个数据湖,每周安排和运行数据检查。我们不使用历史数据和筛选数据,只使用当前 DAG 中正在处理的数据。
分析和生成测试
在我们之前的实现中,我们使用 Pandas Profiling 进行分析,并对测试寄予厚望,如下所示:
并行运行 AWS Lambda,对每个数据集使用 Pandas Profiling 和 GE 测试套件,并将每个数据集存储/服务为静态 S3 网站。
阶跃函数是这样工作的:
作者图片
现在,我们将把概要分析和测试分解成单独的步骤。首先,让我们检查配置文件数据集。
接下来,我们需要基于分析结果生成一个测试套件。因为 Pandas Profiling 默认情况下保存没有失败预期的套件,所以我们将无法配置。让我们通过添加以下内容来覆盖期望类:
之后,您将能够为飞行测试生成器配置您自己的预期:
确保使用新的期望处理器,这样套件就可以保存在亚马逊 S3 上:
运行数据质量保证测试
接下来,让我们弄清楚如何用 GE 引擎开始运行测试。
接下来的两步类似于我在之前的解决方案中描述的步骤:在 Allure Report 中创建一个报表,并将一个数据透视表推送到 Amazon DynamoDB。如果省略这些步骤,为每个数据源创建并行迭代的 StepFunctions 管道将如下所示:
作者图片
要运行管道,需要使用这个模板: file_path 和new _ expectationbool value,默认为“true”——它会为每次运行创建一个新的期望套件。您也可以运行它一次,并将其设置为“false”来开始使用这个测试套件。
这只是一个大概的概念。现在,让我们谈谈使用 Terraform 和部署我们的解决方案。为了解释这一部分,我将火炬传递给普罗维特斯的开发人员叶戈尔·格罗多夫。
DevOps 支持
部署
我们选择使用 AWS 作为平台来运行我们的快速数据质量保证解决方案。它为我们提供了构建可扩展基础设施和以不同方式管理基础设施的所有必要服务。这里我们有两个选择:
- 云的形成
- 将(行星)地球化(以适合人类居住)
目前,我们使用 Terraform 作为主要工具来构建和管理可再生的基础设施。当然,使用它有好处也有坏处,但它非常适合快速数据 QA。
第 1 步—又名“手持”
至此,我们在 AWS 的教育账号中已经有了一个运行快速的数据 QA MVP。我们应该能够在我们的主账户/独立账户中复制它。为此,我们将检查基础设施的哪些部分需要使用 Terraform 来描述。在我们的案例中,它们是:
- S3 配置的桶
- DynamoDB 表
- ECR(三个回购,每个 lambda 一个)
- Lambdas(每步一个,总共三个)
- 阶跃函数
- SSM 参数存储
一旦我们理解了我们需要描述哪些资源,就该创建一个新的 Terraform 项目了。在常规的“terraform init”之前,我们需要添加一个 AWS 提供者。
在 AWS 中,每个资源都有自己的标识符。它可以是“名称”、“id”、“arn”或任何类似的标识符。我们有标识符的键和标识符本身;此外,我们需要在 Terraform 脚本中正确命名“resource ”,以便我们可以命令:“Terraform,请将名为‘my resource’的资源导入到‘terra form _ resource’。my resource’。”之后,我们可以简单地将导入的状态复制到 Terraform 脚本中,瞧!这一资源现在由 Terraform 管理。
步骤 2 —参数化
一旦我们导入了 AWS 资源并且它们由 Terraform 管理,我们需要在运行之前配置 GreatExpectation 库。GE 的常规方法是将配置和插件文件存储在特定的 S3 键下。所以,让我们参数化和模板化它们。
首先是“great _ expecations.yml”文件。这里我们只需要模板化一个参数—“bucket _ name”,如下所示:
此外,我们有一组 GreatExpectation 文件,如“插件”和“自定义样式”。我们应该照原样复制它们,但把它们存放在一个结构僵硬的 S3 桶里。最好的方法是在 Terraform 目录中复制一个所需的文件结构,然后使用带有模板化密钥路径的“aws_s3_bucket_object”。
第 3 步— CI
我们使用 Git 作为版本控制系统。我们将代码库存储在我们自己的 GitLab 服务器上。
因为我们有三个 lambdas,每个都需要自己的 docker 映像,所以我们需要一个地方来创建这些 docker 并将其推送到 ECR。为此,我们将使用 Gitlab CI Runner。有几个基于 Terraform 的开源解决方案,但它们都提供了我们不需要的功能。相反,我们决定建立一个简单的“项目内”地形模块,包括:
- VPC 和网络详细信息
- 带有“launch_template”的 AWS 自动缩放组
- 仅允许 ECR 操作的 CI 用户和 IAM 角色
VPC
我们只需要一个基本的 VPC,带有“aws_internet_gateway”,公共的“aws_subnet”,“aws_route_table”,“aws_route”,“aws_route_table_association”,以及带有 egress 的安全组。
带“launch_template”的 AWS 自动缩放组
由于我们不打算使用 Ansible 这样的供应工具,我们决定将“aws_launch_template”与“aws_autoscaling_group”和一个简单的 sh 模板一起使用,该模板由 Terraform 模板化并在启动时运行。这个脚本安装 docker、docker-machine、gitlab-runner 二进制文件,并运行这个 bin 在 gitlab 服务器上注册 runner。
GitLab Runner
-
安装转轮
-
登记赛跑者
在应用了一个 GitLab-CI 模块后,我们可以在 GitLab UI 中看到一个注册的 runner,我们准备创建一个“gitlab_ci.yml”文件,该文件带有构建 docker 映像并将其推送到 ECR 的指令。此外,我们需要向 CI 管道传递额外的 env 变量,以参数化管道的每个阶段。为此,使用以下 Terraform 代码:
仅允许 ECR 操作的 CI 用户和 IAM 角色
我们不想给那些只使用管道 CI 部分的用户太多的访问权限。为了限制访问,我们只需要创建一个具有 ECR 策略的 AWS 用户:
第四步——总结
现在,我们有:
- Gitlab CI 模块
- 带有 lambdas 等的主模块。
- 根模块具有上述两个模块,一个管理远程状态,以及模块和提供者的变量
以上所有内容都允许我们执行以下用例:
- 向 GreatExpectation 测试套件添加元素或对其进行更改
- 合并对特定 Git 分支的更改
- Gitlab CI 运行一个管道,打包一个新的 Docker 映像并将其推送到 AWS ECR
- 更改 Terraform 中的 docker_image 变量
- 应用地形
结论
作者图片
最终的结果是,我们得到了一个点击式的 Terraform 脚本,可以很容易地为新项目进行配置。一旦我们运行它,我们将有一个基于 Lambda/Step 函数的现成的数据质量管道,可以与任何 BI 仪表板工具一起使用。
要了解更多关于 Provectus 数据质量保证实践的信息,请访问网页
快速 Docker 构建带有缓存(不仅仅是)的 Python
在 Docker build 中安装应用程序依赖项需要很长时间?CI/CD 限制 Docker 缓存的有效性?使用私人回购?…您听说过新的 BuildKit 缓存特性吗?
在 Unsplash 上由 Cameron Venti 拍摄的照片
作为一名开发人员,对我的生产力来说最重要的事情之一是做出改变——构建——测试循环的速度。它目前涉及到用 Python 构建几个 Docker 映像。事实证明,用 Python 快速构建 Docker 并不那么简单,也没有太多好的文章。在我迈向高效构建的旅程中,我学到了比我想要的更多的关于 Docker 缓存的知识,我想在这里与你分享我的发现。
我将首先解释 Docker 为提供的不同的缓存选项,以及新的 BuildKit 后端(Docker 18.09+),并逐步展示如何将它们组合起来,这样您就不会在等待构建管道时多花一秒钟。不耐烦的可以直接跳到文末的完整解决方案。
虽然代码示例显示了一个安装了poems、的 Python 应用程序,但是大多数技术也适用于其他语言或者应用程序在 Docker 中的构建阶段需要很长时间并且缓存会有所帮助的情况。
挑战
有几件事会使快速构建变得具有挑战性:
- 应用程序有许多依赖项,下载和安装需要很长时间。
- CI/CD 作业在我们控制有限的机器上运行。特别是,我们不能依赖于 Docker 缓存的存在。
- 有些依赖项是从私有存储库安装的,需要秘密凭据进行身份验证。
- 生成的图像如此之大,以至于从注册表中推送和提取都要花费不可忽略的时间。
我们想要的是尽可能快的构建、映像拉取和映像推送,即使有这些限制。但是在我们找到解决方案之前,让我们看看我们有哪些工具可以使用。
工具
图片来自makeameme.org
Docker 层缓存
每个人都知道 Docker 图层和缓存——除非图像图层的输入发生变化,否则 Docker 可以重用本地缓存的图层。只需仔细排序 Dockerfile 命令,以避免缓存无效。
外部缓存源
如果我们没有可用的本地缓存,例如在 CI/CD 代理上,该怎么办?解决这个问题的一个不太为人所知的特性是外部缓存源。您可以使用build
命令的**--cache-from**
标志在注册表中提供先前构建的映像。Docker 将检查图像的清单,并提取任何可以用作本地缓存的层。
要让它发挥作用,有几个注意事项。需要 BuildKit 后端——这需要 Docker 版本≥18.09,并在调用docker build
之前设置一个DOCKER_BUILDKIT=1
环境变量。源图像也应该用--build-arg BUILDKIT_INLINE_CACHE=1
构建,这样它就嵌入了缓存元数据。
建造坐骑
当谈到在 Docker 构建中使用缓存目录时,有人可能会认为我们可以从主机挂载它。很简单,对吧?除了不支持。幸运的是,BuildKit 增加了另一个有帮助的特性:构建挂载。它们支持在单个RUN
指令的持续时间内从各种来源挂载一个目录:
RUN --mount=type=cache,target=/var/cache/apt \
apt update && apt-get install -y gcc
有几种类型的安装,例如,
bind
mount 允许您从映像或构建上下文中挂载一个目录;- mount 挂载一个目录,其内容将在两次构建之间被本地缓存。
然而,挂载的内容对于 docker 文件中后面的任何指令都是不可用的。
为了使构建挂载工作,需要在 Dockerfile # syntax=docker/dockerfile:1.3
中包含一个特殊的第一行,并使用DOCKER_BUILDKIT
环境变量启用 BuildKit。
逐步改进构建
现在我们知道了 Docker with BuildKit 提供了什么,让我们将它与一些最佳实践结合起来,尽可能地改进我们的构建时间。
照片由 Unsplash 上的 Viktoria Niezhentseva 拍摄
首先是依赖项,然后是应用程序代码
经常为 Python 图像推荐的第一个技巧是重新排序指令,以便应用程序代码中的更改不会使已安装依赖关系的图层的缓存失效:
现在,只有当pyproject.toml
或锁定文件改变时,具有相关性的层才会被重建。顺便说一下,有些人建议用 pip 而不是 poem 安装依赖项,但是也有的理由不要。
多阶段构建和虚拟环境
另一件显而易见的事情是利用多阶段构建,以便最终映像只包含必要的生产文件和依赖关系:
你可以看到我们在最后阶段使用了一个较小的基础图像(3.8-slim
)和--no-dev
诗歌选项来使结果更小。
我们还添加了一个 Python 虚拟环境。虽然在一个已经被隔离的容器中它看起来是多余的,但是它提供了一种干净的方法来在构建阶段之间转移依赖关系,而不需要不必要的系统包。激活它所需要的只是设置变量PATH
和VIRTUAL_ENV
(一些工具用它来检测环境)。venv 的替代方法是构建车轮文件。
关于诗歌的一个警告是,你应该小心virtualenvs.in-project
的设置。以下是不做什么的简化示例:
COPY ["pyproject.toml", "poetry.lock", "/app/"]
RUN poetry config virtualenvs.in-project true && poetry install
COPY [".", "/app"]FROM python:3.8-slim as finalENV PATH="/app/.venv/bin:$PATH"
WORKDIR /app
COPY --from=build-stage /app /app
这将使生成的映像像以前一样小,构建速度也一样快,但应用程序文件和依赖关系将最终出现在一个最终的映像层中,打破了对拉/推依赖关系的缓存。之前显示的正确版本允许在远程注册表中缓存有依赖关系的层。
传递存储库机密
诗歌通过POETRY_HTTP_BASIC_<REPO>_PASSWORD
等环境变量接受凭证。传递 PyPI 存储库凭证的一个简单的解决方案是用--build-arg
传递它们。不要这样做。
第一个原因是安全。变量将保持嵌入在图像中,你可以用docker history --no-trunc <image>
验证。另一个原因是,如果你使用临时凭证(例如,由你的 CI/CD 提供),在 **--build-arg**
中传递凭证或者通过**COPY**
指令将使缓存的具有依赖关系的层无效!
BuildKit 再次出手相救。新推荐的方法是使用[secret](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md#run---mounttypesecret)
建造坐骑。
- 首先,准备一个包含您的凭证的
auth.toml
文件,例如:
[http-basic]
[http-basic.my_repo]
username = "my_username"
password = "my_ephemeral_password"
-
将它放在 Docker 上下文的之外,或者将其排除在
.dockerignore
之外(否则缓存仍然会失效)。 -
更新 docker 文件,将
# syntax=docker/dockerfile:1.3
作为第一行,并将poetry install
命令改为 -
最后,用
DOCKER_BUILDKIT=1 **docker build** **--secret id=auth,src=auth.toml** ...
构建镜像。
缓存逻辑不考虑构建装载的内容,因此即使凭据发生变化,也将重用已安装依赖项的层。
没有本地缓存的缓存
我们的要求之一是在 CI/CD 作业中也利用 Docker 缓存,这些作业可能没有本地缓存可用。这就是前面提到的外部缓存源和**--cache-from**
可以帮助我们的时候。如果您的远程存储库是my-repo.com/my-image
,您的构建命令将变成:
DOCKER_BUILDKIT=1 docker build \
--cache-from my-repo.com/my-image \
--build-arg BUILDKIT_INLINE_CACHE=1 \
...
这对于单阶段构建来说很好。不幸的是,我们还需要为构建阶段缓存层,这需要为它构建和推送一个单独的映像:
注意,我们在第一个构建命令中使用了[--target](https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage)
来停止在build-stage
阶段,并且第二个构建命令引用了build-stage
和latest
图像作为缓存源。
将缓存图像推送到远程注册表的另一种方法是使用 [docker save](https://github.com/linkerd/linkerd2/pull/891/files)
并将它们作为文件管理。
最后一件事:现在你也推你的构建阶段图像,这是一个好主意,使它也更小。设置PIP_NO_CACHE_DIR=1
ENV
变量可以有所帮助。
使用。dockerignore
最重要的是从您的构建上下文中省略不必要的文件,并使用[.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file)
排除生成 docker 映像。这里有一个你可能想忽略的例子。
获取 docker 构建中的缓存目录
我将提到最后一个技巧,尽管我不推荐它,除非你真的需要它。到目前为止,我们成功地避免了使用 Docker 层缓存重复安装依赖项,除非您更改了依赖项定义(pyproject.toml
或poetry.lock
)。如果我们想重用以前安装的包,即使我们改变了一些依赖关系(就像 does 在本地运行时所做的那样),该怎么办?在poetry install
运行之前,您需要将缓存的 venv 目录放到docker build
容器中。
最简单的解决方案是使用[cache](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md#run---mounttypecache)
构建挂载。缺点是缓存只能在本地使用,不能跨机器重用。还要记住,构建挂载只在单个RUN
指令期间可用,因此您需要在RUN
指令完成之前将文件复制到映像中的不同位置(例如,使用cp
)。
如果您自己在构建主机上管理缓存目录,那么您可以使用[bind](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md#run---mounttypebind-the-default-mount-type)
构建挂载来挂载它。同样的警告只适用于单个RUN
指令。
另一种方法是COPY
来自另一映像的高速缓存目录,例如,先前构建的build-stage
映像。你可以把它拉成另一个阶段(FROM my-image:build-stage as cache
)。棘手的部分是解决先有鸡还是先有蛋的问题:在缓存源可用之前,您的构建第一次就需要工作;而且 Dockerfile 里没有if
。解决方案是参数化缓存阶段所基于的图像:
ARG VENV_CACHE_IMAGE=python:3.8FROM $VENV_CACHE_IMAGE as cache
RUN python -m venv /venvFROM python:3.8 as build-stage
# ...
COPY --from=cache /venv /venv
RUN poetry install --remove-untracked
如果您已经有一个可用的build-stage
映像,将VENV_CACHE_IMAGE
构建参数指向它。否则,使用一些其他可用的图像作为默认图像,RUN python -m venv /venv
指令将确保一个空的/venv
目录可用,这样COPY
就不会失败。
完整的解决方案
让我们总结一下您可以采取哪些步骤来加快构件速度并缩小图像:
- 对 Dockerfile 指令进行重新排序,以便只有
COPY
的依赖项规范位于依赖项安装之前。稍后复制应用程序文件。 - 利用多阶段构建,仅将虚拟环境(或轮子)的必要依赖项复制到最终映像,使其变小。
- 不要将具有依赖关系的应用程序代码与
virtualenvs.in-project = true
混在一起。 - 使用一个
[secret](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md#run---mounttypesecret)
构建挂载来传递存储库凭证。 - 如果本地缓存不可用,使用
[--cache-from](https://docs.docker.com/engine/reference/commandline/build/#specifying-external-cache-sources)
重用注册表中的图像。这可能需要将构建阶段的一个单独的映像推送到注册表中。 - 如果你绝对需要在
docker build
期间获得一个缓存目录到一个容器,使用[cache](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md#run---mounttypecache)
或[bind](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md#run---mounttypebind-the-default-mount-type)
构建挂载,或者COPY
从另一个映像获取它作为额外的构建阶段。请记住,要正确实施所有选项都有点棘手。
由此产生的Dockerfile
可能是这样的:
为 Python 应用程序定制的 Docker 文件,用于优化 Docker 缓存
(出于安全原因,我还添加了指令,使应用程序不能在root
下运行。你可以在这篇伟大的文章中找到这个和其他有用的提示。)
在您的配置项/光盘中构建和推送映像可能如下所示:
使用构建阶段缓存支持构建上述 docker 文件的脚本
如您所见,在 Docker 中使用 Python 进行适当的缓存并不简单。但是当你知道如何使用新的 BuildKit 特性时,Docker 可以为你工作,而不是与你作对,并做许多繁重的工作。
使用 FastAPI 的快速简单的 Python APIs
最好的 python 框架之一!
Solaiman Hossen 在 Unsplash 上拍摄的照片
FastAPI 是一个现代的、基于 python 的高性能 web 框架,用于创建 Rest APIs。它的主要特点是速度快,编码速度提高了 300%,bug 少,易于使用,对生产友好。
关于 Fast API 的唯一缺点是它相对较新,它的社区不像其他框架如 Flask 那么大,但我认为它会快速增长,因为许多公司如微软、网飞和优步已经在使用它。
在这篇文章中,我将向您展示如何使用 Fast API 创建一些简单的 GET 和 POST APIs。
装置
pip install fastapi
我们还需要一个 ASGI 服务器,用于像uvicon这样的产品。
pip install uvicorn
你好世界
让我们从创建最简单的 API 开始。它将返回一个 JSON 消息“Hello World”。
用下面的代码创建一个“main.py”文件。
#import FastAPI
from fastapi import FastAPI
#create a FastAPI instance
app = FastAPI()
#create a path operation
@app.get(“/”)
#define the path operation function
def root():
return {“message”: “Hello World”}
如您所见,使用 FastAPI 创建 API 有 4 个主要步骤。第一步是导入它,然后创建一个 FastAPI 实例(在我们的例子中称为 app)。
之后,我们必须创建一个路径操作。这意味着我们必须设置 URL 路径(在我们的例子中是'/',但我们可以设置任何类似'/helloworld ')及其操作。我们所说的操作是指 HTTP 方法,如 GET、POST、PUT 和 DELETE(在我们的例子中,操作是 get )。
最后,我们必须定义路径操作函数。换句话说,一个函数返回我们想从我们的 API 中得到的东西(在我们的例子中是一个带有 Hello World 消息的 JSON。
现在,通过终端导航到 main.py 文件夹,并运行以下命令:
uvicorn main:app --reload
您应该会看到以下输出。
这意味着我们的 API 运行在 http://127.0.0.1:8000。让我们看看我们得到了什么。
路径参数
假设我们想要创建一个 GET API,它接受两个数字作为输入,并返回它们的和。要添加参数你只需要把它们作为路径操作函数的参数。
from fastapi import FastAPI
app = FastAPI()
[@app](http://twitter.com/app).get("/addition")
def sum(a, b):
return {"Result": a+b}
可以通过添加符号“”向 URL 传递参数?"然后参数之间用符号“&”隔开。让我们试试下面的方法:
[http://127.0.0.1:8000/addition?a=12&b=13](http://127.0.0.1:8000/addition?a=12&b=13)
就这么简单。您还可以设置参数的类型,如整数或字符串,这样,如果用户输入不同的类型,它将返回一个警告。
@app.get("/addition")**def** sum(a:int, b:int):
**return** {"Result": a**+**b}
让我们抽出一根绳子,看看我们会得到什么。
[http://127.0.0.1:8000/addition?a=12&b=aa](http://127.0.0.1:8000/addition?a=12&b=aa)
发布 API
我将向您展示如何创建一个 POST API,它将 JSON 文件作为输入。让我们看一个简单的例子。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class inputs(BaseModel):
a:int
b:int
c:int
d:int
[@app](http://twitter.com/app).post('/show_data')
def show_data(data: inputs):
return({"data":[data.a,data.b,data.c,data.d]})
我们必须导入 BaseModel 并创建一个 BaseModel 类,它包含 JSON 文件的变量(在我们的例子中是 a,b,c,d)。然后,我们必须将该类设置为操作函数中的一个变量(在我们的例子中,数据:输入)。现在,我们可以使用类变量的名称和它的变量名称(如 data.a)来访问函数内部的变量,以访问变量 a、data.b 等。
FastAPI 自动为我们提供了 SwaggerUI ,这是一个天才且非常有用的 UI,允许我们可视化 API 的资源并与之交互。它还可以用于测试,甚至是像上面这样的 POST APIs。您可以通过在 APIs URL 中添加 /docs 来访问它。
[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)
正如你在上面的视频中看到的,我们已经测试了我们的 API,它运行得很完美。
案例研究:通过 REST API 服务于机器学习模型
对于这个例子,我们将使用著名的虹膜数据集训练一个简单的 ML 模型来预测虹膜的类型(Setosa、Versicolour 和 Virginica)。然后,我们将使用 FastAPI 创建一个 POST API,它将输入特性并返回预测。
首先,让我们训练我们的模型并将其保存到 pickle 文件中。
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
import pandas as pd
iris = datasets.load_iris()
features=pd.DataFrame(iris['data'])
target=iris['target']
model=LogisticRegression(max_iter=1000)
model.fit(features,target)
import pickle
pickle.dump(model, open('model_iris', 'wb'))
现在,我们准备创建我们的 API。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class iris(BaseModel):
a:float
b:float
c:float
d:float
from sklearn.linear_model import LogisticRegression
import pandas as pd
import pickle
#we are loading the model using pickle
model = pickle.load(open('model_iris', 'rb'))
[@app](http://twitter.com/app).post('/make_predictions')
async def make_predictions(features: iris):
return({"prediction":str(model.predict([[features.a,features.b,features.c,features.d]])[0])})
现在,如果你用下面的 JSON 输入上面的 API,你会得到一个预测。
{
"a": 1.1,
"b": 3.3,
"c": 5,
"d": 1
}{
"prediction": "2"
}
总结一下
FastAPI 是 Rest APIs 的最佳 Python 框架之一,因为它快速、简单且对生产友好。它的社区将会快速发展,因为像网飞、优步和微软这样的公司已经在使用它了。你不需要任何比我们在这篇文章中提到的更多的东西,所以开始尝试吧!
最初发表于 https://predictivehacks.com。
Python 中的快速要素工程:影像数据
使您的图像更适合输入 ML 系统
乔纳森·博尔巴在 Unsplash 上的照片
“在任何一种数据丰富的环境中,寻找模式都很容易;平庸的赌徒就是这样。关键在于确定这些图案代表的是噪音还是信号。”
― 内特·西尔弗
本文是我的“快速特征工程”系列的第 2 部分。如果您还没有读过我的第一篇关于表格数据的文章,那么我请求您在这里查看一下:
本文将研究在执行图像处理作为我们机器学习工作流程的一部分时要遵循的一些最佳实践。
图书馆
import random
from PIL import Image
import cv2
import numpy as np
from matplotlib import pyplot as plt
import json
import albumentations as A
import torch
import torchvision.models as models
import torchvision.transforms as transforms
import torch.nn as nn
from tqdm import tqdm_notebook
from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR10
调整图像大小/缩放图像
调整大小是该领域深度学习实践者所做的最基本的转换。这样做的主要原因是为了确保我们的深度学习系统接收到的输入是一致的。
调整大小的另一个原因是减少模型中参数的数量。较小的维度意味着较小的神经网络,因此节省了我们训练模型所需的时间和计算能力。
信息丢失怎么办?
当你从大图中缩小尺寸时,一些信息确实会丢失。然而,根据您的任务,您可以选择愿意为训练时间和计算资源牺牲多少信息。
例如, 对象检测任务 将要求您保持图像的纵横比,因为目标是检测对象的准确位置。
相比之下,图像分类任务可能需要您将所有图像调整到指定的大小(224 x 224 是一个很好的经验法则)。
(来源)
调整大小后,我们的图像看起来像这样:
(来源)
为什么要进行图像缩放?
与表格数据类似,为分类任务缩放图像可以帮助我们的深度学习模型的学习速率更好地收敛到最小值。
缩放可确保某个特定维度不会支配其他维度。关于这一点,我在 StackExchange 上找到了一个很棒的答案。你可以在这里 读到 。
一种特征缩放是标准化我们的像素值的过程。我们通过从每个通道的像素值中减去每个通道的平均值,然后通过标准偏差对其进行划分。
当训练用于分类任务的模型时,这是特征工程的流行选择。
注意:与调整大小一样,在执行对象检测和图像生成任务时,可能不希望进行图像缩放。
上面的示例代码演示了通过标准化来缩放图像的过程。还有其他形式的缩放,如居中和正常化。
扩充(分类)
增强图像背后的主要动机是由于计算机视觉任务需要可观的数据。通常,由于多种原因,获得足够的图像用于训练可能被证明是具有挑战性的。
图像增强使我们能够通过稍微修改原始样本来创建新的训练样本。
在这个例子中,我们将看看如何为分类任务应用普通增强。我们可以使用albuminations库的现成实现来做到这一点:
高斯模糊、随机裁剪、翻转(来源)
通过应用图像增强,我们的深度学习模型可以更好地概括任务(避免过度拟合),从而提高其对未知数据的预测能力。
增强(物体检测)
Albumentations 库也可用于为其他任务(如对象检测)创建增强功能。对象检测要求我们在感兴趣的对象周围创建边界框。
当试图用边界框的坐标来注释图像时,处理原始数据可能被证明是具有挑战性的。
幸运的是,有许多公开和免费可用的数据集,我们可以使用它们来创建对象检测的增强管道。一个这样的数据集是 象棋数据集 。
该数据集包含棋盘上 606 个棋子的图像。
除了图像之外,还提供了一个 JSON 文件,其中包含与单个图像中每个棋子的边界框相关的所有信息。
通过编写一个简单的函数,我们可以在应用增强后可视化数据:
作者图片
现在,让我们尝试使用白蛋白创建一个增强管道。
包含注释信息的 JSON 文件有以下键:
dict_keys([‘info’, ‘licenses’, ‘categories’, ‘images’, ‘annotations’])
images
包含关于图像文件的信息,而annotations
包含关于图像中每个对象的边界框的信息。
最后,categories
包含映射到图像中棋子类型的键。
image_list = json_file.get('images')
anno_list = json_file.get('annotations')
cat_list = json_file.get('categories')
image_list
:
[{'id': 0,
'license': 1,
'file_name': 'IMG_0317_JPG.rf.00207d2fe8c0a0f20715333d49d22b4f.jpg',
'height': 416,
'width': 416,
'date_captured': '2021-02-23T17:32:58+00:00'},
{'id': 1,
'license': 1,
'file_name': '5a8433ec79c881f84ef19a07dc73665d_jpg.rf.00544a8110f323e0d7721b3acf2a9e1e.jpg',
'height': 416,
'width': 416,
'date_captured': '2021-02-23T17:32:58+00:00'},
{'id': 2,
'license': 1,
'file_name': '675619f2c8078824cfd182cec2eeba95_jpg.rf.0130e3c26b1bf275bf240894ba73ed7c.jpg',
'height': 416,
'width': 416,
'date_captured': '2021-02-23T17:32:58+00:00'},
.
.
.
.
anno_list
:
[{'id': 0,
'image_id': 0,
'category_id': 7,
'bbox': [220, 14, 18, 46.023746508293286],
'area': 828.4274371492792,
'segmentation': [],
'iscrowd': 0},
{'id': 1,
'image_id': 1,
'category_id': 8,
'bbox': [187, 103, 22.686527154676014, 59.127992255841036],
'area': 1341.4088019136107,
'segmentation': [],
'iscrowd': 0},
{'id': 2,
'image_id': 2,
'category_id': 10,
'bbox': [203, 24, 24.26037020843023, 60.5],
'area': 1467.752397610029,
'segmentation': [],
'iscrowd': 0},
.
.
.
.
cat_list
:
[{'id': 0, 'name': 'pieces', 'supercategory': 'none'},
{'id': 1, 'name': 'bishop', 'supercategory': 'pieces'},
{'id': 2, 'name': 'black-bishop', 'supercategory': 'pieces'},
{'id': 3, 'name': 'black-king', 'supercategory': 'pieces'},
{'id': 4, 'name': 'black-knight', 'supercategory': 'pieces'},
{'id': 5, 'name': 'black-pawn', 'supercategory': 'pieces'},
{'id': 6, 'name': 'black-queen', 'supercategory': 'pieces'},
{'id': 7, 'name': 'black-rook', 'supercategory': 'pieces'},
{'id': 8, 'name': 'white-bishop', 'supercategory': 'pieces'},
{'id': 9, 'name': 'white-king', 'supercategory': 'pieces'},
{'id': 10, 'name': 'white-knight', 'supercategory': 'pieces'},
{'id': 11, 'name': 'white-pawn', 'supercategory': 'pieces'},
{'id': 12, 'name': 'white-queen', 'supercategory': 'pieces'},
{'id': 13, 'name': 'white-rook', 'supercategory': 'pieces'}]
我们必须改变这些列表的结构,以创建一个高效的管道:
现在,让我们创建一个简单的增强管道,水平翻转我们的图像,并为边界框添加一个参数:
最后,我们将创建一个类似于 Pytorch 提供的 数据集类 的数据集。为此,我们需要定义一个实现方法__len__
和__getitem__
的类。
以下是对自定义数据集进行迭代时的一些结果:
作者图片
作者图片
因此,我们现在可以轻松地将这个自定义数据集传递给数据加载器来训练我们的模型。
特征抽出
您可能听说过预训练模型用于训练图像分类器和其他监督学习任务。
但是,您知道吗,您还可以使用预先训练的模型来提取图像的特征。
简而言之,特征提取是一种降维形式,其中大量像素被简化为更有效的表示。
这主要用于无监督的机器学习任务,如反向图像搜索。
让我们尝试使用 Pytorch 的预训练模型从图像中提取特征。为此,我们必须首先定义我们的特征提取器类:
请注意,在第 4 行中,创建了一个新模型,原始模型的所有层都保存为最后一层。您会记得,神经网络中的最后一层是用于预测输出的密集层。
然而,由于我们只对提取特征感兴趣,所以我们不需要这最后一层。因此,它被排除在外。
然后,我们通过将 torchvision 的预训练resnet34
模型传递给ResnetFeatureExtractor
构造器来利用它。
让我们使用著名的 CIFAR10 数据集 (50000 张图像),并对其进行循环以提取特征。
CIFAR10 数据集(来源)
我们现在有 50000 个图像特征向量的列表,每个特征向量的大小为 512(原始 resnet 模型的倒数第二层的输出大小)。
print(f"Number of feature vectors: {len(feature_list)}") #50000
print(f"Number of feature vectors: {len(feature_list[0])}") #512
因此,这个特征向量列表现在可以被诸如 KNN 的统计学习模型用来搜索相似的图像。
如果你已经走到这一步,那么非常感谢你阅读这篇文章!我希望你有美好的一天!😄
👉 文章中使用的代码
下次见!✋
参考资料:
Python 中的快速要素工程:表格数据
特征工程
使您的表格数据更适合输入 ML 系统
亚历山大·辛恩在 Unsplash 上的照片
作为数据科学家,我们的工作是从噪音中提取信号。”
― 丹尼尔·唐克朗 ,顾问/顾问
通常被称为数据科学中的秘方,特征工程可能是数据清理工作流程中最重要的一步。
您的特征越好,模型的预测能力就越强。
在本文中,我们将探讨使用 Python 中流行的数据科学库从数据中有效地设计和提取要素的许多方法。
表格数据是数据科学从业者使用的最常见的数据类型。在这种格式中,数据以行和列的形式排列。
我们来看看表格数据面临的一些常见问题,以及如何解决。
🔢处理数字数据
让我们使用sklearn.datasets
模块创建一个具有 10000 行和 25 个特征的合成数据集。
X_df 的内容
缩放、标准化和规范化
训练线性模型(如线性/逻辑回归和 SVM)时,缩放数据集会对模型性能产生巨大影响。
因为这些模型是使用距离度量来优化的,缩放确保具有较大值的特征不会支配模型拟合的结果。
在我们的第一种缩放方法中,我们将使用由sklearn
提供的MinMaxScaler
来将每个特征缩放到值 -1 和 1 之间。
X_df 的内容
MinMaxScaler
接受一个名为feature_range
的参数,用户可以在其中指定所需的范围。根据您的特征是否具有正值,保持范围为 -1 到 1 或 0 到 1 被认为是最佳实践。
在引擎盖下,这是正在计算的:
其中特征中的元素与特征的最小值的差除以特征的范围。
另一种形式的缩放被称为标准化,其中每个特征被转换为具有平均值 0 和标准偏差 1。这对于正常发布我们的功能非常有用。
StandardScaler
模块可用于标准化我们的功能:
**
X _ df _ 标准化的内容
标准化工作如下:
其中特征的每个单独元素减去特征集的均值并除以标准差。
到目前为止,我们已经研究了在特征级操作的缩放方法。像单位长度 归一化这样的方法也支持跨观测值的缩放。
当数据具有大量等效特征时,如文本数据,这种类型的标准化非常有用,因为每个单词都被视为一个特征。
Normalizer
缩放每个观察值,使其单位范数长度为 1。
**
X_df_normalized 内容
以下是归一化的公式:
**
分母是观察值的 l2 范数 ,它是每个特征中观察值的平方和的平方根。
创建多项式特征
两种情况下可能需要多项式要素:
- 当您怀疑特征与目标变量有非线性关系时
- 当您怀疑特性相互依赖时(交互)。
*(10000, 350)*
我们可以清楚地看到,我们最初只有 25 个特征的数据现在有 350 个了!😮
注意:构建多项式特征将导致特征爆炸,因此请确保使用良好的特征选择实践。
变换特征
Scikit Learn 还使创建自定义变形器以应用于一个或多个功能变得非常容易。你所要做的就是定义一个函数,并将它传递给FunctionTransformer
的一个实例。
如果您正在使用 Pandas 数据框,您可以使用数据框可用的.apply
方法来转换您的数据,而不是使用FunctionTransformer
。
扔掉
宁滨是一种像处理分类变量一样处理数值变量的方法。宁滨涉及到将我们的数字数据分解成个离散的单元。
Numpy 有一个名为.digitize
的方法,可以帮助轻松创建媒体夹:
如果您正在处理数据帧,您也可以使用 Pandas 提供的.cut
方法来创建 bin:
注意:Pandas 输出与 Numpy 输出略有不同。在 Pandas 中,我们必须指定数值数据的下限和上限,以避免生成未知值。Pandas 输出还以间隔的形式输出数据,这与 Numpy 输出相反,后者将每个值分配给一个 bin 号。
👫处理分类数据
到目前为止,我们只研究了数字数据的处理。分类数据可以大致分为:
- 名义变量——有两个或两个以上类别,但缺乏任何排序的变量。例如,男孩,女孩可以称为一个名义变量
- 序数—具有特定关联顺序的变量。例如,一个与温度相关的特征具有类别:非常冷、冷、暖、热、非常热。
由于机器学习算法只理解数字,而不理解其他任何东西,因此我们必须应用适当的转换,以便我们的算法吸收数据。
让我们使用另一个来自著名的 UCI 机器学习库的关于汽车的数据集。这里可以找到。
**
标签编码
标签编码是一种编码形式,我们将每个类别编码为一个数字。这种编码在基于树的算法中特别有用。
让我们看看如何将标注编码应用于数据集的一个要素:
我们看到特性engine_type
有 7 个不同的类别。
在创建了一个将每个类别映射到一个数字的字典之后,我们可以使用 Pandas 提供的.map
方法轻松地转换这个特性。
对于中级 Python 开发人员,您可能会发现使用字典理解以编程方式创建映射字典更加直观:
标签编码的另一种方式是sklearn
提供的开箱即用解决方案:
当我们对顺序变量进行编码时,标签编码是我们选择的编码方式。
注意:确保编码与类别的顺序相称。
一个热编码
一种热编码技术是我们将每个类别编码为一个二进制值的向量,向量的长度是我们特征中唯一类别的数量。
一个热点编码示例
尽管一键编码可以增加我们数据中的特征数量,但是大多数列将会稀疏。
当我们使用基于回归的模型时,这种类型的编码特别有用。
就像这里的大多数例子一样,sklearn
也有一个现成的热编码实现:
注:
OneHotEncoder
模块有一个名为sparse
的参数,允许用户校准编码器的输出。默认情况下,
sparse
被设置为true
,因此输出数组是一个消耗较少内存的稀疏数组。
将分类变量转换为数值变量
一个非常简单的方法是简单地获得每个类别的计数,然后用它替换类别。
我们可以结合熊猫提供的groupby
和transform
方法来实现这一点:
您可能还想按多列分组并使用计数。:
创建新的分类特征
这是一个我不知道的技巧,直到我最近读了 Kaggle 特级大师 Abhishek Thakur 写的一本名为“接近(几乎)任何机器学习问题”的书。
通过 Pandas,从现有的分类特征创建新的分类特征非常容易。
例如,我们可以从两个现有特征fuel_type
和engine_type
中创建一个名为fuel_type_engine_type
的新特征,如下所示:
我们看到,通过将特征转换为类型字符串,我们可以利用运算符重载和矢量化运算来优雅地创建新特征。
此技巧可用于使用多列分类数据创建多个要素。
注意:在决定组合哪些功能时,了解一些关于您正在处理的数据的领域知识可能会有所帮助。这将帮助您构建有意义的功能,而不是构建多余的功能。
📈处理时间序列数据
我知道时间序列数据也许应该归入数字数据的范畴。然而,由于处理这类数据的技术与数字数据相比略有不同,我认为应该有一个单独的部分。
让我们使用约翰·霍普金斯大学 CSSE 提供的新冠肺炎数据来演示如何轻松地在时间序列数据上构建要素:
注意:这里我们看到“Date”列有字符串格式的日期。为了将这些转换成日期时间特性,我们将
pd.to_datetime
应用于每个观察值
提取特征
从日期时间对象中提取特征非常容易。我们可以使用.dt
属性来访问序列中的日期时间值,并返回多个新特性:
汇总统计数据
我从 Abhishek Thakur 的书中学到的另一个技巧是如何将提取的时间序列特征与目标变量的聚合特征结合起来。
在这种方法中,我们使用从时间序列数据中提取的特征和目标变量特征(“已确认”)来创建每个国家的综合特征:
然后,我们可以使用Country/Region
特性作为键,将这个表与我们的原始表合并。
滞后特征和移动平均线
如果您想在当前观察中添加过去的信息,滞后特性尤其有用。
熊猫图书馆提供了一个名为.shift
的方法来开箱即用:
移动平均线是不同数据子集的一系列平均线。通过从短期波动(如股票市场价格)中“去噪”时间序列数据,它们在平滑趋势方面特别有用。
类似于创建滞后特征,为了创建移动平均线,我们可以在 Pandas 中使用.rolling
方法。.rolling
方法采用一个名为window
的参数,在这里您可以指定由数字组成的窗口的大小来计算平均值。
然后我们可以在这个窗口上应用.mean
函数来计算移动平均值。
通过一个名为 tsfresh 的库,可以为时间序列数据创建更多的特性。这里我就不深究了。你可以在这里阅读 tsfresh 的文档。
因此,我们已经看到了许多设计、提取和转换我们现有特征的方法,以创建新的有意义的特征。我希望你们都喜欢这篇文章😄
我知道我还没有介绍如何处理图像和文本数据。请放心,将来也会有关于如何处理这些问题的文章!✊
如果您想了解如何处理数据集中的缺失值,请点击此处查看本文:
*
最后,我强烈建议您阅读这两本书,我发现它们在学习特征工程时非常有用:
https://www.amazon.in/Approaching-Almost-Machine-Learning-Problem-ebook/dp/B089P13QHT https://www.amazon.in/Machine-Learning-Python-Cookbook-Preprocessing-ebook/dp/B07BC3LFKT
下次见,再见!✋*
快速 SQL 学习技巧
图 1。典型的 SQL 查询。作者使用模式 SQL 编辑器创建的图像
SQL 代表结构化查询语言是一种非常重要的领域特定语言,用于关系数据库管理系统(RDBMS)的编程和数据管理。SQL 在许多方面都非常重要,尤其是在结构化数据中,用户编写特定的命令来查找不同变量和数量之间的关系。
SQL 最初是由 IBM 研究人员唐纳德·钱伯林和 Raymond F. Boyce 在 20 世纪 70 年代早期开发的,其目的是检索和处理 IBM 准关系数据库系统 r 中存储的数据。从那时起,SQL 成为最常用的数据库语言,并在 1986 年成为 asi 和 1987 年成为 ISO 的标准。
SQL 的主要目的之一是查询关系数据库中的数据。SQL 具有由 ISO/IEC SC 32 定义和维护的标准语言语法,但也存在其他修改。这使得 SQL 在不进行调整的情况下不能完全移植到不同的数据库系统中。SQL 的其他扩展包括通过与其他语言(如 Java、Python、Perl 等)的 DBMS 集成来适应过程和面向对象的编程。
在本文中,我将讨论一些有用的 SQL 学习技巧,这些技巧将帮助您加快 SQL 学习。这些技巧是主观的,并不详尽,因为 SQL 是一种非常扩展的语言。本文面向那些计划学习 SQL 的人,也面向那些正在学习 SQL 的人。在这里,我假设读者有一个 SQL 编辑器或编辑器平台,可以编写 SQL 命令和语句来执行查询。
1.SQL 的语言元素
SQL 有几种语言元素,可以分为不同的类别。其中一些类别包括:
- 查询 : 用于 SQL 中,根据特定的条件检索数据库中的数据。
- 子句 :是查询和语句的重要 SQL 组成部分。
- 表达式 :是用于生成标量值或由列和行组成的表的 SQL 的重要组成部分。
- 关键词 :是 SQL 语句、查询、表达式的组成部分。它们被定义为保留或非保留的单词。
- 谓词 :是评估为真/假/未知的语句和查询的 SQL 组成部分。它们用于更改 SQL 控制流或限制语句和查询的效果。
2.选择 →从 → WHERE 条件语句
假设您有一个数据库,并想在其上执行操作。SQL 中的每个数据库都是由列和行组成的表。在使用 SQL 时,人们经常需要查看数据库并查看其列和行,以便对数据库的组成部分有一个大致的了解。这个操作是 SQL 的基础之一。
为此,SQL 具有以下易于记忆的语法:
*Syntax 1***SELECT** column1, column2, column3, ....columnN
**FROM** table name
**WHERE** condition1 **AND/OR/NOT** condition2 ... **AND/OR/NOT** conditionM ;
在上面的 SQL 语法 1 中, SELECT 语句用于 only 选择用户想要显示的列。来自关键字的用于指定包含 SELECT 语句的 N 列的表/数据库的名称。
WHERE 子句用于过滤表/数据库的一些记录。该子句由用户希望检查是否满意的语句组成。 WHERE 子句可以由任意数量的条件组成。但是,如果使用了多个条件,则需要使用 运算符 和/或、非、或它们的组合来过滤列中的数据。
所以关于 select 语句要记住的关键点是上面的语法 1。所以尽量记住以下连续的语句:从 → WHERE 中选择 → 。接下来,记住 SELECT 语句指的是列名,来自关键字的指的是使用的表/数据库,而 WHERE 子句指的是用户调查的特定条件。中的条件,其中子句是指表格列上的条件。
需要记住的重要一点是, WHERE 子句是可选的,可以省略,而 SELECT 和 FROM 是必需的,不能省略。如果需要从给定的表中选择所有的列,那么在 SELECT 语句后面的符号(*)就可以完成这项工作。
另一个要点是 SQL 关键字不区分大小写。如选择或选择或选择或选择等没有区别。,如本文顶部的图所示。
3.聚合函数
SQL 有五个基本聚合函数,它们是在语句、查询和表达式中使用的特定关键字。这些聚合函数是: MAX()、MIN()、COUNT()、AVG() 和 SUM() 。
SQL 聚合函数通常用于包含数字数据的列,即标量。所有这些函数都可以包含在以下 SQL 语法中:
Syntax 2**SELECT** **aggregate_function**(column name)
**FROM** table name
**WHERE** condition ;
语法 2 中的“aggregate _ function=MAX()或 MIN() 或 AVG() 或 COUNT() 或 SUM() ”。语法 2 可以扩展,以在 SELECT 语句和 WHERE 子句中包含更多选项。
COUNT() 函数统计给定列表中非空的行数, COUNT (列名)或整个表中非空的行数 COUNT (*)。它可以用于数字和非数字列数据。
MAX() 和 MIN() 函数返回给定列中的最高值和最低值。这些函数可用于数值和非数值数据。如果给定列有数值数据,则 MIN (列名)返回该列中的最小数值。另一方面, MAX (列名)返回最大数值。如果数据为非数字数据, MIN (列名)返回以字母“A”开头的列条目,而 MAX (列名)返回以字母“Z”开头的列条目。
SUM (列名)函数返回给定列中所有数值的总和。该函数只能用于包含数字数据的列。它忽略具有空条目的行。
AVG (列名)返回给定列中数值数据的平均值。它只能用于包含数字数据的列。它忽略具有空值的行。
为了容易地记住集合函数的用法,只要试着记住语法 2 并重复它。这个简单的语法允许您记住如何在 SQL 查询中使用所有五个 SQL 聚合函数。
4.连接函数
图二。作者创造的形象
在 SQL 联接中,子句用于根据表中的相关列组合不同表中的行。
在查询中基本上使用了四个 SQL 基本连接关键字。这些关键字被称为:内连接、左连接、右连接和全连接。所有这些 SQL 连接关键字都可以很容易地记忆下来,并与以下 SQL 语法一起使用:
Syntax 3**SELECT** Table(1 or 2).column_name, Table(1 or 2).column_name,...,Table(1 or 2).column_name
**FROM** Table1
**join_keyword** Table2
**ON** Table1.Matching_column_name = Table2.Matching_column_name
语法 3 中, join_keyword = 内连接或左连接或右连接或全连接。你可能会注意到在关键字之后,join_keyword 跟在关键字之后。使用 SQL 连接时要记住的一件重要事情是语法 3 的形式,这并不难记忆。一旦你记住了,那么连接就很简单了。
语法 3 中的 SELECT 语句选择用户想要显示的列。这些列可以是表 1 和表 2 中的列的组合。表 1 和表 2 都必须有一个相关的列来执行连接功能。
INNER JOIN 关键字选择表 1 和表 2 中具有匹配值的所有记录。这在图 2 的左上侧象征性地显示为两个相交的集合。
LEFT JOIN 关键字返回表 1(左表)中的所有记录和表 2(右表)中的匹配记录,如图 2 右上角所示。
右连接关键字返回表 2(右表)中的所有记录和表 2(左表)中的匹配记录,如图 2 左下方所示。
FULL JOIN (或 FULL OUTER JOIN )关键字返回在左表(Table1)或右表(Table2)中匹配的所有记录。
如果有两个以上的表要连接,那么情况会稍微复杂一些。在这种情况下,通常需要执行 SQL 嵌套联接。我在这篇文章中没有涉及这个主题。
结论
从我上面展示的 SQL 中可以看出,一次性记住不同的 SQL 函数和关键字是可能的,因为它们共享相同的正式语法。事实上,您可以在语法 2 中看到,所有四个基本的 SQL 聚合函数共享相同的正式语法。这一事实使得在 SQL 语句和查询中记住它们的功能成为可能。
同样的事情也发生在连接子句和关键字上。这些连接关键字共享相同的 SQL 语法,这使得用户更容易记住它们。
要记住的关键点是,一旦你记住并理解了语法 2 和语法 3 是如何工作的,那么在更复杂的 SQL 查询(比如嵌套查询)中应用这些语法就更容易了。
如果你喜欢我的文章,请与你可能对这个话题感兴趣的朋友分享,并在你的研究中引用/参考我的文章。不要忘记订阅将来会发布的其他相关主题。
使用 Zip“固定”Python 对象
图片由 Alexas_Fotos 在 Pixabay 上拍摄
Python 的一个技巧使得多个可重复项的使用变得更加容易
像大多数其他编程语言一样,Python 有许多常见的可迭代对象,如 list(在其他语言中通常称为 array)、set 和 dictionary。但是,有这样一个“Pythonic 式”的 iterable 并不太常见,它就是“zip”。
这个“zip”不是用来压缩的,应该理解为它的浅层含义:把对象固定在两个或多个 iterables 中(比如 lists)。在这篇文章中,我将介绍
- Python zip 的基本用法
- 如何在解包时使用 zip)
- 如何解决“水桶效应”
基本用法
照片由 Myriams-Fotos 在 Pixabay 上拍摄
首先,让我们用一些对象创建两个列表。请注意,任何 iterables 都可以与zip
一起工作,列表也是如此。
keys = ['name', 'age', 'message']
values = ['Chris', 33, 'Thank you for reading my articles!']
这里是zip
最基本的用法,就是把两个列表扣在一起。
for item in zip(keys, values):
print(item)
假设这两个列表是拉链的两个金属条,那么其中的每个对象将是“拉链齿”。当我们一起“拉动”滑块后,“牙齿”就会相应地锁在一起。然后,每个“行”将拥有两个列表中的两个对象。
注意:在 **values**
列表中,数字“33”是一个整数,其他元素是字符串。所以 Python zip 不关心 iterables 中元素的类型,非常灵活!
我们可以轻松地将结果放入一个列表中,而不是循环并打印这些值,如下所示。
list(zip(keys, values))
事实上,最方便的用法是在压缩列表上生成一个字典。
dict(zip(keys, values))
获取不带元组的两个元素
有时,没有必要将结果放入另一个 iterables 中。如果我们想使用压缩后的结果而不使用烦人的元组,我们可以简单地从 zip 中获取两个值,如下所示。
for key, value in zip(keys, values):
print(f'{key}: {value}')
超过两个
如果我们把一个 Python 字典放入一个 zip 中会怎么样?字典中的值将被忽略,只有按键会被视为“金属条”。
让我们建立一个字典,以及一个额外的实验清单。
rows = [1, 2, 3]
my_dict = dict(zip(keys, values))print(my_dict)
那么,我们来试一试。
for item in zip(rows, my_dict):
print(item)
和我提到的完全一样,只取键,忽略值。要解决这个问题,只需将字典的键和值分别传递到 zip 中。
for item in zip(rows, my_dict.keys(), my_dict.values()):
print(item)
还可以看出,zip 支持两个以上的可迭代对象。
带拆包的拉链
照片由 Alexas_Fotos 在 Pixabay 上拍摄
解包是 Python 中另一个独特的概念。如果您不太熟悉它,您可能还会在一些 Python 代码中看到星号*。这就是“拆包”。
让我用一个例子来解释一下。假设我们有这样一个二维列表,它在概念上也可能被当作一个矩阵。
matrix = [
[1,2,3],
[1,2,3],
[1,2,3]
]
我们都知道矩阵是一个 3 元素的列表,每个元素也是一个 3 位数的列表。现在,假设我们要压缩 3 个“子列表”并使用相应位置的数字,带解包的压缩是最佳解决方案。
for item in zip(*matrix):
print(item)
其实不难被理解。解包只是将 3 个子列表从它们的父列表中取出。我有一个想法,保证你能理解。参见下面的代码,它产生完全相同的结果。
for item in zip(matrix[0], matrix[1], matrix[2]):
print(item)
拉链最长,克服水桶效应
还有一个zip
的限制。也就是说,压缩结果的长度取决于所有可重复项中最短的一个。这和经典的“水桶效应”很像。一般是指一个水桶能装多少水,取决于最短的木板。
让我们再举一个例子来重现这个问题。
keys = ['name', 'age', 'message']
values = ['Chris', 33]for key, value in zip(keys, values):
print(f'{key}: {value}')
在上面的例子中,我们的keys
列表有 3 个元素,但是values
列表只有两个。在压缩的结果中,我们丢失了第三个键message
,因为在values
列表中没有更多的元素可以提取出来与之匹配。
为了解决这个问题,我们可以使用itertools
库中的另一个方法,这是一个内置的 Python 库,因此它默认情况下与 Python 一起提供。
from itertools import zip_longestfor key, value in zip_longest(keys, values):
print(f'{key}: {value}')
酷!现在我们有了钥匙message
。由于另一个列表中没有对应的值,所以只是用None
填充。
Python 3.10 中的新特性
值得一提的是,Python 3.10 中发布了一些新特性(参见 PEP-618)
https://www.python.org/dev/peps/pep-0618/
在 PEP-618 中提出并接受了一个名为strict
的新的zip
标志,它将强制检查zip
中可重复项的长度。如果长度不同,会升起一个ValueError
。
list(zip(range(3), ['fee', 'fi', 'fo', 'fum'], strict=True))Traceback (most recent call last):
...
ValueError: zip() argument 2 is longer than argument 1
摘要
在本文中,我介绍了“zip ”,它是 Python 中最具 Python 风格和最有用的工具之一。它的基本用法非常有用,我们可以看到它在许多 Python 项目中被广泛使用。此外,拆包技术也经常和zip
一起使用。最后,我展示了 Python zip 的一个约束,可以称之为“桶效应”,但它可以在 Python 内置库中解决。
https://medium.com/@qiuyujx/membership
如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)
利用机器学习和粒子群优化加快钻井速度
如何找到钻井中优化机械钻速的最佳点
钻头(来源:迈克·博勒加德
O 优化是每一项工程设计的核心——波音公司利用优化来设计飞机机翼的最佳拓扑结构,以提高飞行效率,通用电气公司利用优化来设计最佳的风力涡轮机叶片,使其旋转更快以产生更多的电力,还有更多其他很酷的例子。在石油和天然气行业,优化用于许多方面,如钻井。我们在这篇文章中的任务是强调在这个领域的应用。
首先,我们需要了解钻井的组成部分。钻柱是一个整体或组件,由下图所示的部件组成。钻铤(由钢筋制成的厚壁管件)提供的重量与钻头直接接触。这个重量被称为钻压或 WOB ,定义为破碎岩石所需的施加到钻头上的向下的力。由于钻头正在旋转,测量每分钟的转数或 RPM 。
钻柱组成及钻压(来源:宋等,2019 )
钻速或 ROP 定义为单位时间内所钻深度距离的单位。钻速由随钻测量(MWD)仪器实时测量。如果在 1 分钟内可以达到 1 英尺的距离,我们可以计算 ROP 如下:
ROP 越高,可以达到的距离越快。公司总是想尽可能快地钻探以节省时间,因为时间就是金钱。因此,他们雇佣钻井工程师对钻井作业进行良好的设计,包括优化机械钻速。
司钻能从地面控制的唯一变量是 WOB 和每分钟转数。其他变量(PHIF、VSH、SW 和 KLOGH)是常量变量,因为它们代表地层。因此,为了最有效地钻凿地层,WOB 和每分钟转数应该调节得足够充分。
不幸的是,ROP 并不总是随着 WOB 和 RPM 的增加而成比例地增加。在许多情况下,随着 WOB 和每分钟转数的不断增加,转速增加,直到开始下降。这个点通常被称为方正点。在这一点上,钻头没有有效地切割岩石。如果在建立点之后施加额外的 WOB,钻头的效率会变得更低。这就是为什么我们需要找到 ROP 最佳的“最佳点”。
在本文中,我们将讨论机器学习在钻井机械钻速优化中的另一个重要应用。这篇教程文章附有 Jupyter Notebook 中的源代码,可以在这里访问。
资料组
我们将要使用的数据集是由两个原始数据排列而成的;北海 Volve 油田 15/9-F-15 号井的实时钻井数据和计算岩石物理产量(CPO)测井数据。数据集在 GitHub 这里。请记住,在之前的文章中我们已经多次使用过 Volve 数据集,因为它是开源的。
数据集的前 10 行
数据集由 8 列组成;深度(测量深度)、WOB(钻压)、SURF_RPM(地面每分钟转数)、ROP_AVG(平均钻速)、PHIF(地层孔隙度)、VSH(页岩体积)、SW(含水饱和度)和 KLOGH(对数渗透率)。WOB、SURF_RPM 和 ROP_AVG 是钻井参数,而其余的是岩石物理参数。
问题陈述
数据集被可视化为测井显示,我们可以观察钻井参数和储层的岩石物理性质如何随深度变化。
钻井和地球物理测井数据的可视化——yo hanes nu wara
让我们注意一下 3480-3500 米井段,在该井段,机械钻速下降到 0.002 米/秒。这种突然中断可能是由两个因素造成的;预期或意外的原因。预期的原因可能是高地层压力,以便司钻避免事故。意外原因是 WOB 和转速不足。
因为我们没有地层压力的详细资料,我们假设这种突然的破裂是意料之外的。当我们在 3480 米深度观察时,当机械钻速下降到 0.002 米/秒时,WOB 约为 31000 牛顿,每分钟转数为 2。我们假设 WOB 和每分钟转数不足以保持机械钻速高于此值。
因此,通过这篇文章我们将回答两个问题;
- 是什么原因导致机械钻速在 3480 米处突然下降?
- 优化机械钻速需要多大的 WOB 和每分钟转数?
在进入 ML 和优化之前,我们做探索性的数据分析。下面是数据集中一些独立变量的配对图。我们可以突出一些有趣的关系。机械钻速似乎与 VSH (页岩体积)相关。这似乎与直觉相反,因为我们通常认为,在 VSH 高的页岩地层中,机械钻速会变低。机械钻速似乎与 PHIF(地层孔隙度)没有相关性。此外,数据集中的点往往聚集在低 VSH、低 PHIF 和低 WOB 。
独立变量对图—约哈内斯·努瓦拉
接下来,我们继续使用梯度推进机器模型来制作 ROP 的预测模型。
用于钻速预测的梯度推进机
开始机器学习部分,ROP_AVG 作为预测目标从剩余的列中分离出来。然后,数据集被分成具有 20%测试大小的训练集和测试集。我们制作了一个管道,由一个标准的定标器和我们使用的模型梯度推进组成。为我们的模型设置了两个超参数;min_samples_leaf=6
和max_depth=20
。管道适合列车组,并对模型进行了评估。训练的 R 平方分数是 95%,测试的 R 平方分数是 79%。
梯度推进机或 GBM 是一种集成方法,通过创建各种更简单的估计器的集成来工作。它被称为 boosting,因为集合模型比单个估计器表现得好得多。它的工作原理是对树逐一求和;第二棵树作为一个系综添加到第一棵树上(称之为【D1】)。我们有一个目标函数,叫它 f 。 f 和 D1 之间的差(或残差)是将被下一个第三棵树最小化的残差。它创造了一个新的合奏。然后在 f 和 D2 之间计算这个残差,一个新的系综诞生了,重复这个过程。
梯度推进方法图解(来源)
我们编译了模型,根据新的输入进行预测。例如,我们希望预测给定输入的机械钻速,如以下代码所示(储层孔隙度为 20%,页岩体积为 50%,含水饱和度为 100%,渗透率为 500 毫达西,深度为 4000 米,钻压为 50000 牛顿,转速为 2 转/分)。该模型预测的机械钻速为 0.008 米/秒
粒子群优化
最后,我们试图优化 3480 米深度处的机械钻速,在该深度处机械钻速会突然中断。我们使用该模型来生成作为 WOB 和 RPM 的函数的 ROP 的“预测空间”。为此,我们设定了一系列 WOB 和 RPM 值,并保持其他输入变量不变。恒定输入变量是从我们在 3480 米的数据中获得的
- 深度:3480 米
- PHIF: 0.09
- VSH: 0.1
- 软件:1
- KLOGH: 0.01 毫英寸
- WOB:范围(17,000–90,000)北部
- 转速:范围(1.5–2.5)
下面是生成预测空间的代码。
这导致了以下预测空间;
ROP-yo hanes nu wara 的预测空间
从该图中,我们看到,在 3480 米深度,WOB 在 42000N 以上达到了最高机械钻速,每分钟转数范围为 1.8-2。
我们可以清楚的找到 ROP 下降的原因!在数据中,我们知道 WOB 只有 31,000 N,低于 WOB 优化钻速的可接受窗口。
更进一步,我们将使用粒子群优化或 PSO 找到在该深度做出最佳 ROP 的 WOB 和 RPM 的值。
粒子群优化(PSO) 是一种受动物群体(候鸟和蜜蜂)行为启发的优化算法。在任何优化问题中,都有一个称为目标函数的函数,它是作为优化目标的定义明确的函数。全局解位于搜索空间的某个地方。粒子群优化算法首先在搜索空间的随机位置上安排一些粒子(或群体)。这些粒子具有初始速度和方向,将通过多次迭代加速,直到它们找到全局解。
粒子群优化(个人)
我们使用了 PySwarm 包来使用 PSO 来解决我们的优化问题。首先,我们定义目标函数。我们的目标函数是由名为pipe
的管道构成的,包括我们已经建立的梯度推进模型。该函数检索数组X
中的所有输入变量。接下来,我们定义搜索的上限和下限。在这个优化问题中,我们想要搜索 WOB 和 RPM 的值。因此,只有这些变量在上面给出的范围内具有下限和上限。
最后,我们运行粒子群算法。我们如代码所示设置超参数,如swarmsize
(群体粒子数)200、omega
(粒子速度比例因子)0.3、phip
(搜索远离粒子最佳位置的比例因子)0.5、phig
(搜索远离群体最佳位置的比例因子)0.7、maxiter
(最大迭代次数)1000、minstep
(搜索终止前群体最佳位置的最小步长)
上述 PSO 实现输出优化 ROP 的 WOB 和 RPM 的值,以及实现的最佳 ROP。
初始结果与优化结果
从上表可以得出结论,在 3480 米深度,司钻应该增加 WOB 并保持转速,以增加机械钻速至最佳点。
结论
我们已经展示了如何使用梯度推进机和粒子群优化来优化钻井中的钻速。以下是我们在本文中提出的两个问题的答案;
- 由于 WOB 不足 31000 牛顿,机械钻速在 3480 米深度下降到 0.002 米/秒
- 在 3480 米深度的最佳机械钻速为 0.0055 米。WOB 大约为 74000 牛顿,转速为 2 转/分钟时,可以达到最佳机械钻速。
在未来,像钻孔突然中断这样的问题可以通过在生产线上进行优化来避免。我们不只是拯救🕒,也是这个💰!
请关注我即将发布的关于我在我们惊人的能源行业中的更多人工智能实验的文章!💡
使用 Scikit-Learn 的 HalvingGridSearchCV 实现更快的超参数调谐
对半网格搜索与穷举网格搜索的比较
罗伯塔·索奇在 Unsplash 上拍摄的照片
如果你是 Scikit-Learn 的粉丝,随着 0.24.0 版本的发布,2020 年的圣诞节提前了几天。 model_selection 模块中的两个实验性超参数优化器类属于新特性:halvinggridsearccv和 HalvingRandomSearchCV 。
像他们的近亲 GridSearchCV 和 RandomizedSearchCV 一样,他们使用交叉验证来寻找最优超参数。然而,他们的连续减半搜索策略“使用少量资源开始评估所有候选,并使用越来越多的资源迭代选择最佳候选”,而不是独立搜索超参数集候选默认资源是样本数,但用户可以将其设置为任何正整数模型参数,如梯度增强舍入。因此,减半方法有可能在更短的时间内找到好的超参数。
我的实验
我通读了 Scikit-Learn 的“网格搜索和连续减半之间的比较”示例,但是因为总共需要 11 秒来运行,所以我仍然不清楚使用减半和穷举方法的真实影响。所以我决定设立一个实验来回答以下问题:
- HalvingGridSearchCV 比 GridSearchCV 快多少?
- HalvingGridSearchCV 是否仍然选择与 GridSearchCV 相同的超参数集?
我将运行并比较 3 个搜索:
- GridSearchCV
- HalvingGridSearchCV 使用默认的" n_samples"
resource
- HalvingGridSearchCV 使用 CatBoost 的“n_estimators”作为
resource
升级 Scikit-Learn
第一步是将您的 Scikit 版本升级到 0.24.0,并确保您可以导入正确的版本。
# !! pip install scikit-learn --upgrade
import sklearn
print(sklearn.__version__)**0.24.0**
加载数据集
我使用 Kaggle 的 Ames,IA 房价数据集进行了测试。它有 1,460 个观察值和 79 个特征。因变量是家庭的SalePrice
。如果您对数据集上的一些探索性数据分析感兴趣,我推荐您阅读本笔记本。
import numpy as np
import pandas as pd
DEP_VAR = 'SalePrice'
train_df = pd.read_csv('../kaggle/input/house-prices-advanced-regression-techniques/train.csv')\
.set_index('Id')
y_train = train_df.pop(DEP_VAR)
创建管道和模型
我还写了一个脚本叫做 pipeline_ames.py 。它实例化了一个包含一些特性转换的管道和 CatBoostRegressor 。我在下面画出了它的视觉表现。(你可以在我的上一篇文章中读到更多关于我的特征工程方法的信息。)
from sklearn import set_config
from sklearn.utils import estimator_html_repr
from IPython.core.display import display, HTML
from pipeline_ames import pipe
set_config(display='diagram')
display(HTML(estimator_html_repr(pipe)))
实验控制
grid_search_params
字典包含 3 次搜索中使用的控制参数。我对param_grid
进行了三重交叉验证,它包含 4 个 CatBoost 超参数,每个参数有 3 个值。结果以均方根对数误差(RMSLE)测量。
from sklearn.metrics import mean_squared_log_error, make_scorer
np.random.seed(123) # set a global seed
pd.set_option("display.precision", 4)
rmsle = lambda y_true, y_pred:\
np.sqrt(mean_squared_log_error(y_true, y_pred))
scorer = make_scorer(rmsle, greater_is_better=False)
param_grid = {"model__max_depth": [5, 6, 7],
'model__learning_rate': [.01, 0.03, .06],
'model__subsample': [.7, .8, .9],
'model__colsample_bylevel': [.8, .9, 1]}
grid_search_params = dict(estimator=pipe,
param_grid=param_grid,
scoring=scorer,
cv=3,
n_jobs=-1,
verbose=2)
试验
1.GridSearchCV
基线彻底的网格搜索花了将近 33 分钟对我们的 81 个候选人进行 3 重交叉验证。我们将会看到 HalvingGridSearchCV 过程是否可以在更短的时间内找到相同的超参数。
%%time
from sklearn.model_selection import GridSearchCVfull_results = GridSearchCV(**grid_search_params)\
.fit(train_df, y_train)pd.DataFrame(full_results.best_params_, index=[0])\
.assign(RMSLE=-full_results.best_score_)**Fitting 3 folds for each of 81 candidates, totalling 243 fits
Wall time: 32min 53s**
2.具有 n 个样本的 HalvingGridSearchCV
在第一次对半网格搜索中,我对resource
使用默认的‘n _ samples ’,并将min_resources
设置为使用总资源的 1/4,即 365 个样本。我没有使用 22 个样本的默认min_resources
计算,因为它产生了可怕的结果。
对于两个减半搜索,我使用了 2 的factor
。该参数确定连续迭代中使用的n_candidates
和n_resources
,并间接确定搜索中使用的迭代总数。
factor
的倒数决定了n_candidates
保留的比例——在这种情况下,是一半。所有其他候选都被丢弃。因此,正如您在下面的日志中看到的,我的搜索中的 3 次迭代分别有 81、41 和 21 个候选项。factor
和前一次迭代的n_resources
的乘积决定了n_resources
。我的 3 次迭代搜索使用了 365、730 和 1460 个样本。- 总迭代次数由
factor
增加n_resources
多少次而不超过max_resources
决定。如果您希望最终的迭代使用所有的资源,您需要将min_resources
和factor
设置为max_resources
的因子。
%%time
from sklearn.experimental import enable_halving_search_cv
from sklearn.model_selection import HalvingGridSearchCVFACTOR = 2
MAX_RESOURCE_DIVISOR = 4
n_samples = len(train_df)
halving_results_n_samples =\
HalvingGridSearchCV(resource='n_samples',
min_resources=n_samples//\
MAX_RESOURCE_DIVISOR,
factor=FACTOR,
**grid_search_params
)\
.fit(train_df, y_train)**n_iterations: 3
n_required_iterations: 7
n_possible_iterations: 3
min_resources_: 365
max_resources_: 1460
aggressive_elimination: False
factor: 2
----------
iter: 0
n_candidates: 81
n_resources: 365
Fitting 3 folds for each of 81 candidates, totalling 243 fits
----------
iter: 1
n_candidates: 41
n_resources: 730
Fitting 3 folds for each of 41 candidates, totalling 123 fits
----------
iter: 2
n_candidates: 21
n_resources: 1460
Fitting 3 folds for each of 21 candidates, totalling 63 fits
Wall time: 34min 46s**
第一次减半搜索没有产生好的结果。它实际上比彻底搜索花费的时间要长一点。使用我的 compare_cv_best_params 函数,我们看到它只找到了第九个最佳超参数集。
from compare_functions import *compare_cv_best_params(full_results, *[halving_results_n_samples])\
.style.applymap(lambda cell: ‘background: pink’ if cell == 9 else)
3.具有 n 个估计量的 HalvingGridSearchCV
在第二次减半搜索中,我使用 CatBoost 的n_estimators
作为资源,并将第一次迭代的min_resources
设置为使用这些估计量的四分之一,同时将factor
设置为 2。
%%time
halving_results_n_estimators =\
HalvingGridSearchCV(resource='model__n_estimators',
max_resources=1000,
min_resources=1000 // MAX_RESOURCE_DIVISOR,
factor=FACTOR,
**grid_search_params
)\
.fit(train_df, y_train)**n_iterations: 3
n_required_iterations: 7
n_possible_iterations: 3
min_resources_: 250
max_resources_: 1000
aggressive_elimination: False
factor: 2
----------
iter: 0
n_candidates: 81
n_resources: 250
Fitting 3 folds for each of 81 candidates, totalling 243 fits
----------
iter: 1
n_candidates: 41
n_resources: 500
Fitting 3 folds for each of 41 candidates, totalling 123 fits
----------
iter: 2
n_candidates: 21
n_resources: 1000
Fitting 3 folds for each of 21 candidates, totalling 63 fits
Wall time: 22min 59s**
这种减半搜索产生了我们希望看到的结果。它提前 10 分钟完成,因此比穷举网格搜索快了大约 30%。重要的是,它还找到了最佳的超参数集。
compare_cv_best_params(full_results, *[halving_results_n_samples,
halving_results_n_estimators])\
.style.apply(lambda row: \
row.apply(lambda col: \
'background: lightgreen' if row.name == 2 else ''), \
axis=1)
结论
我的 HalvingGridSearchCV 实验结果喜忧参半。使用默认的“n_samples”资源产生了缓慢且次优的结果。如果您没有使用大量的样本,限制它们可能不会节省您的时间。
然而,使用 CatBoost 的n_estimators
作为资源在更短的时间内产生了最佳结果。这与我自己手动调整梯度增强超参数的经验相符。我通常可以从验证日志中很快判断出超参数集是否值得进行更多轮次的提升。
如果你觉得这篇文章有帮助,请告诉我。这篇博文的原始笔记本可以在这里找到。
关注我并关注 Scikit-Learn 关于培训模型的更多帖子。谢谢!
使用 mbleven 快速计算 Levenshtein 距离
莱文斯坦永远服用?如果你的 levenshtein 算法需要很多时间,并且你的边界参数小于 3,请尝试使用 mbleven。
什么是 levenshtein 距离?
Levenshtein 距离是将字符串 a 转换为字符串 b 所需的最小插入、删除和符号替换次数。
举例: 考虑字符串 a: 鼠标 &字符串 b: 莫尔斯
弦 a 与弦 b 之间的 Levenshtein 距离为 2。您需要从字符串 a 中删除 u 并插入 r 以将字符串 a 转换为字符串 b.
levenshtein 距离还有另一个修改:
- Damerau Levenshtein 遵循与 Levenshtein 距离完全相同的方法,但您也可以使用换位(相邻符号的交换),因此,它使 Levenshtein 更快、更有效。
在上面的例子中,字符串 a 和字符串 b 之间的 Damerau-Levenshtein 距离是 1。你只需要用 r 替换字符串 a 中的 u 就可以将字符串 a 转换为字符串b
虽然看起来很简单,但是如果你在一个熊猫数据帧中有数千行,那么 Levenshtein 距离需要花费很多时间来运行。
mbleven 来拯救—
与 Levenshtein 不同,mbleven 是一种“基于假设的算法”。它将首先列出将一个字符串转换为另一个字符串的所有可能的假设。
上述例子的可能假设:
- 如果 I 插入 r 是否可以将字符串 a 转换为字符串 b ?
- 如果我删除 u 字符串 a 可以转换成字符串 b 吗?
- 如果我用代替 u ,字符串 a 能转换成字符串 b 吗?
- ….
mbleven 将逐一检查所有的假设。所有的假设都可以在 O(n)次内计算出来。
完整的代码及其实现可以在这里查看:https://github.com/fujimotos/mbleven
mbleven 可以确认是否可以使用提到的 k-bound 将一个字符串转换成另一个字符串&它还可以返回两个字符串之间的编辑距离。提到的几个例子是:
*>>> from mbleven import compare
>>> compare("meet", "meat")
1
>>> compare("meet", "eat")
2
>>> compare("meet", "mars") # distance 3
-1*
最后一个示例返回-1,因为这两个字符串之间的距离是 3 编辑距离,默认情况下,该算法的上限是 2 编辑距离。
参考文献—
**
https://github.com/fujimotos/mbleven
使用 GPU 或 TPU 进行更快的机器学习训练
Google Colab 可以从 GitHub 或 Drive 访问任何公开的 Jupyter 笔记本
机器学习 Jupyter 笔记本在 Colab 上免费运行。照片由 Nana Dua 在 Unsplash 上拍摄
为什么要用 Google Colab?
您可以在本地计算机上使用 Jupyter 笔记本。Google Colab 在许多方面改进了 Jupyter 笔记本。以下是使用 Google Colab 的七个最有力的理由:
- 你可以从 GitHub 库中获得任何一个公开的 Jupyter 笔记本。
- 您可以将任何
.ipynb
文件加载、编辑并保存到与 Colab 登录相关的 Google Drive 中。每个项目都有一个独立的谷歌账户和不同的谷歌驱动是很有帮助的。
注意:你可以在 Google Drive 上为任何项目文件夹创建 Git 账户。每个团队成员都在各种不同的本地计算机上运行。他们只需要一个浏览器和互联网连接。您的团队可以通过云在地理上完全分散。
3.您可以配置多代 NVIDIA GPU 中的一款。
4.您可以提供多代谷歌 TPU 中的一个。
5.您可以配置多核 CPU。
6.谷歌 Colab 免费。此外,你可以升级到每个账户每月 9.99 美元的高级版本。
7.Colab 笔记本有许多 Jupyter 笔记本的有用扩展。
从 GitHub Repo 加载文件到 Colab
在浏览器中,前往[https://colab.research.google.com](https://colab.research.google.com)
。一个指向 Google Colab 的新标签打开:
图 Google Colab 的入口。
如果你是 Colab 的新手,在Recent
中唯一的文件是Welcome to Collaboratory
。由于我不是新来的,你可以在Recent
里数五个文件。
从 GitHub 加载文件
点击 GitHub,观察:
图 2:点击 GitHub。
输入您想要浏览的 GitHub 帐户。我进入了bcottman
,我的 GitHub 顶级库。
图 3:选择 bcottman/paso 回购
从回购bcottman/paso
中,我选择了文件bcottman/paso/integration_test_pre_all.ipynb
。
图 4:选择文件bcottman/paso/integration_test_pre_all.ipynb.
这导致文件bcottman/paso/integration_test_pre_all.ipynb
被加载到 GCP(谷歌云平台)的 Colab 浏览器中。
图 5:文件bcottman/paso/integration_test_pre_all.ipynb loaded into Google Colab.
从 Google Drive 加载文件
您可以创建一个 Google Drive,然后为任何项目文件夹创建一个 Git 帐户。你要去[https://colab.research.google.com](https://colab.research.google.com.Going)
。安装谷歌账户的谷歌硬盘。当您点击File|Open notebook
时,Google Drive 中的所有文件都会出现:
图 6:点击File|Open notebook.
选择colab_itils.ipynb
文件:
图 Google Drive 中的顶层文件。
供应多代 NVIDIA GPU 中的一款
点击Runtime|Change runtime type:
配置 Nvidia GPU:
图 8:点击Runtime|Change runtime type
:配置 Nvidia GPU
图 9:选择 GPU。
通过以下方式检查 Nvidia GPU 的配置状态:
The from tensorflow.python.client import device_lib
device_lib.list_local_devices()
输出:
[name: "/device:CPU:0"
device_type: "CPU"
memory_limit: 268435456
locality { }
incarnation: 17311008600223054265,
name: "/device:GPU:0"
device_type: "GPU"
memory_limit: 14674281152
locality {
bus_id: 1
links { } }
incarnation: 7680686309919727928
physical_device_desc: "device: 0,
name: Tesla T4, pci bus id: 0000:00:04.0, compute capability: 7.5"]
提供了 14.67 GB 快速内存的 Nvidia Telsa T4。
提供谷歌 TPU
要设置谷歌 TPU,请在“笔记本设置”中选择 TPU:
图 10:选择 TPU。
结论
在这篇短文中,我展示了如何:
- 您可以从 GitHub 存储库中获取任何公共文件。
- 您可以加载、编辑和保存任何
.ipynb
文件到与 Colab 登录相关的 Google Drive。
3.您可以配置多代 NVIDIA GPU 中的一款。
4.您可以提供多代谷歌 TPU 中的一个。
Google Colab 的一个关键功能是团队成员可以使用 GitHub 上的共享文件在项目上进行协作。此外,每个团队成员都可以在自己的 Google Drive 上创建自己的开发沙盒。
云支持远程工作。编码快乐!
更快的机器学习版本和跟踪:使用 FDS 的例子
使用 FDS,一个开源工具,快速简单地对你的机器学习项目进行版本控制
FDS,快速数据科学,是一个开源工具,使机器学习快速&的版本控制变得容易。它将 Git 和 DVC 结合在一起,负责代码、数据和模型版本控制。
FDS 会帮助你:
- 使用智能版本控制向导🧙♂️.,通过推荐每个文件应该被跟踪的位置来避免错误
- 通过统一命令(如
git status
+dvc status
=fds status
)自动化重复性任务 - 通过提供以人为中心的 UX,使版本控制更快、更容易使用、更友好——想要保存新版本并将其推送到您的共享遥控器,只需
fds save
就可以了。
快速数据科学,作者图片
这个博客是如何使用 FDS 来版本化你的机器学习项目的分步指南。我们将跟踪“肺炎检测”项目,在该项目中,我们训练一个 TensorFlow 模型来对患病和健康的胸部 x 光图像进行分类。本项目中使用的数据集取自“胸部 X 射线图像(肺炎)”ka ggle 竞赛。通过以下详细步骤,您将获得使用 FDS 的实践经验。
肺炎检测数据示例,图片由作者提供
在这篇博客中,我们将介绍如何使用 FDS 执行以下操作:
- 在本地机器上初始化和配置 Git 和 DVC。
- 使用 Git 和 DVC 通过一个命令跟踪项目文件。
- 将文件推送到 Git 和 DVC 远程。
- 只需一个命令,即可自动对所有项目文件进行版本控制、跟踪、提交和推送
项目设置
我们将首先从名为“Pneumonia-Detection”的终端创建一个新目录,并移动到该目录中。然后,我们将创建一个虚拟环境,将其添加到。gitignore 文件,激活它,通过运行pip install fastds
安装 FDS。
注: 因为 DVC 也可以用 brew 安装,所以我们没有把它作为依赖包添加到 FDS。但是,如果 FDS 发现 DVC 没有安装在虚拟环境中,它会建议您安装 DVC。
Mac 和 Linux
$ mkdir Pneumonia-Detection && cd Pneumonia-Detection
$ python -m .venv venv
$ echo .venv/ >> .gitignore
$ source .venv/bin/activate
$ pip install fastds
Windows 操作系统
$ mkdir Pneumonia-Detection && cd Pneumonia-Detection
$ py -m venv .venv
$ echo .venv/ >> .gitignore
$ .venv/Scripts/activate.bat $ pip install fastds
接下来,我们将初始化 Git 和 DVC。我们可以使用fds init
命令来初始化这两个工具,而不是使用这两个工具。
FDS init,Gif 作者
让我们在 DAGsHub 上打开一个存储库,并将其命名为“肺炎检测”。
新存储库设置,按作者分类的图像
接下来,我们将通过运行以下命令,用我们的本地目录配置存储库的 Git 和 DVC 远程设备:
$ git remote add origin https://dagshub.com/<DAGsHub user- name>/Pneumonia-Detection.git
$ dvc remote add origin https://dagshub.com/<DAGsHub user-name>/Pneumonia-Detection.dvc
$ dvc remote modify origin --local auth basic
$ dvc remote modify origin --local user <DAGsHub user-name>
$ dvc remote modify origin --local password <your token>
添加项目文件
我们准备将文件添加到本地目录中。对于这个任务,我们将使用dvc get
命令从 DAGsHub 下载文件。请注意,该命令仅在本教程中是必需的。我选择使用它,这样你就可以按照教程访问这些文件。
注意: 原始数据集很大。我们将使用较小版本的数据集来减少下载、版本控制和上传时间。如果要使用完整的数据集,跳过第一个命令,直接从 Kaggle 竞赛 下载,解压到 *Pneumonia-Detection/data/raw-data*
下。
$ dvc get https://dagshub.com/nirbarazida/Pneumonia-Detection-FDS-Demo data/raw-data -o data/raw-data
$ dvc get https://dagshub.com/nirbarazida/Pneumonia-Detection-FDS-Demo eval
$ dvc get https://dagshub.com/nirbarazida/Pneumonia-Detection-FDS-Demo model/ -o model/
$ dvc get https://dagshub.com/nirbarazida/Pneumonia-Detection-FDS-Demo src
现在,该项目包含以下目录:
data/
-保存分成三个子目录的原始数据图像:train、val(验证)和 test。eval/
-保存关于型号及其性能的信息。model/
-拥有最佳性能的预处理模型。src/
-保存项目的代码文件,包括 Python 模块和 Jupiter 笔记本。
项目的树,作者的图像
用 Git + DVC = FDS 跟踪文件
此时,我们想用 Git 和 DVC 跟踪项目中的文件。该任务需要以下步骤:
- 选择和跟踪 DVC 的大文件/目录。
- 使用 Git 跟踪指针/管道文件。
- 用 Git 跟踪项目的其余文件。
当使用 Git 和 DVC 来版本化项目时,我们经常执行这些动作。这种重复的工作可能会很麻烦,并且对于一些用户来说,不直观。这正是我们创建fds add
向导的原因!
与 imgflip.com 一起创建的图像
因为我们想要对所有的项目文件进行版本化,所以我们将运行fds add .
。
FDS 添加,Gif 作者
项目的所有文件都被版本化,并准备好被推送!但是等等,在我们运行 push 命令之前,我们需要先提交文件。fds commit
命令将dvc commit
和git commit
封装成一个。它首先提交对 DVC 的更改,将带有更新哈希的指针文件添加到 git,然后立即将这些更改(加上任何其他阶段的更改)提交到新的 Git 提交。在我们的例子中,FDS 将认识到在 DVC 跟踪的文件中没有任何改变;因此,它将有效地只提交 Git 跟踪的文件,这正是我们所期望的。
$ fds commit “Track all the project files with FDS”
此时,我们希望确保所有文件都已提交。为此,我们将运行fds status
命令,检查 Git 和 DVC 跟踪的文件的状态。
FDS 状态,作者 Gif
女士们先生们,请系好安全带……正式推送时间到了!
为了推送我们的文件,我们将使用fds push
命令...你猜对了——推送由 Git 和 DVC 跟踪的文件!让我们在 DAGsHub 上检查存储库的新状态。
存储库的新状态,按作者分类的图像
正如我们所见,Git 和 DVC 跟踪的所有文件都被推到了远程。不仅如此,我们可以在一个地方看到项目的所有组件,包括代码、数据、模型和管道。
将流程缩短为一个命令
一条捷径。斯蒂芬·斯坦鲍尔 / Unsplash 摄影
如果您不熟悉 Git、DVC 或 FDS,并且不习惯使用这些命令,或者只是想让您的生活更简单,那么fds save
命令就是为您准备的!通过运行这个命令,FDS 将使用 Git 和 DVC 对所有项目文件进行版本控制、跟踪、提交和推送。为了展示这个命令的用法,我们将下载一个处理过的数据目录并运行fds save
命令。
$ dvc get [https://dagshub.com/nirbarazida/](https://dagshub.com/nirbarazida/Pneumonia-Classification)[Pneumonia-Detection-FDS-Demo](https://dagshub.com/nirbarazida/Pneumonia-Detection-FDS-Demo) data/processed -o data/processed
$ fds save “Add processed data directory”
让我们在 DAGsHub 上检查存储库的新状态。正如我们所看到的,DVC 跟踪了处理过的数据目录,Git 跟踪了更新过的 data.dvc 指针文件,两者都被成功地推送到 DAGsHub。
摘要
我们已经到了本教程的结尾,但是我们共同的旅程才刚刚开始。
与 makememe.org 一起创建的图像
FDS 是完全开源的!
虽然我们的开发人员不断提高 FDS 的能力,但我们欢迎您为 FDS 做出贡献,并获得永恒的荣耀。您可以通过以下方式参与:
使用 Python 和深度学习加快笔记速度
格伦·卡斯滕斯-彼得斯在 Unsplash 拍摄的照片
使用基于深度学习的 OCR 转录 pdf 幻灯片
做笔记的管道
传统的讲座通常附带一套 pdf 幻灯片。传统上,记录这类讲座的过程包括从 pdf 中复制或转录大量内容。
最近,我一直在尝试通过使用 OCR(对象字符识别)来自动转录 pdf 幻灯片,以在 markdown 文件中直接操作它们的内容,从而避免手动复制和粘贴 pdf 的内容,从而实现这一过程的自动化。
在本文中,我将向您展示如何使用基于深度学习的 OCR 自动将 pdf 幻灯片转换为文本。
为什么不使用传统的 pdf 转文本工具?
我之所以不选择使用传统的 pdf 文本工具,是因为我发现它们往往会带来更多的问题,而不是解决它们。我尝试使用传统的 python 包,但是它们带来了一些问题,比如必须用复杂的正则表达式模式解析最终输出,所以我决定尝试一下对象检测和 OCR,看看是否可以做得更好。
步伐
接下来的步骤是:
- 将 pdf 转换成图像
- 检测并识别图像中的文字
- 展示示例输出
在这种情况下,我主要修改了这个库中的代码,它使用了对 CTPN 模型的 pytorch 修改,以及来自 pytorch_ctpn 的代码用于文本检测,以及来自 CRNN 模型的代码用于文本识别。
现在,让我们来看一下每一步。
1.将 pdf 转换成图像
我将使用 David Silver 的《强化学习导论》中的 pdf 幻灯片。让我们首先编写一些代码,使用pdf2image
包将每张幻灯片转换成 png 格式。
现在我有了所有的图像,
图片作者。pdf 中的所有幻灯片。
让我们在每张幻灯片上运行文本检测和识别。
2.检测和识别图像中的文本
为此,我们将使用来自 ocr.pytorch 资源库的文本检测器。按照那里的说明下载模型,并将它们保存在checkpoints
文件夹中。
在这里,我们设置输入和输出文件夹,然后对所有输入图像(转换后的 pdf 幻灯片)运行一个循环,然后通过运行位于ocr
模块中的检测和识别模型的single_pic_proc()
函数。然后,我们将输出保存到输出文件夹。
检测继承自 Pytorch 的 CTPN 模型,识别模型继承自 Pytorch 的 CRNN 模型,两者都存在于ocr
模块中。
3.展示示例输出
检测输出示例:
图片作者。文本检测输出的示例。
文本识别输出:
- AboutRL
Characteristics of Reinforcement Learning
What makes reinforcement learningdifferent from other machine
learning paradigms?
There isnosupervisor,only areward signal
Feedback is delavyed,not instantaneous
Time really matters(sequential,non ii.d data)
Agent sactions affectthe subseauent datait receives
不再复制和粘贴
我喜欢这种方法的原因是,你最终可以拥有一个真正强大的工具来转录各种类型的文档,从检测和识别手写笔记到检测和识别照片中的随机文本。
拥有自己的 OCR 工具来处理您经常交互的内容,比依赖外部软件来处理您想要转录的每个文档要好。
对我来说,这是一个有趣的机会,可以探索 OCR,并建立一个管道来快速转录 pdf 幻灯片附带的讲座。
你可以在这里查看源代码。
如果你喜欢这篇文章,请在 Twitter 、 LinkedIn 上联系我,并在 Medium 上关注我。谢谢,下次再见!😃
参考
- ocr.pytorch 知识库
- pytorch.ctpn
- CRNN
- CTPN
- 大卫·西尔弗关于强化学习的讲座
CPU 上更快、更平滑、更小、更准确和更鲁棒的人脸对齐模型
思想和理论
人脸标志检测器的训练策略、实现优化和新的评价方法。
使用和不使用 GTX 训练的正面人脸图像的 DAN、ERT 和 LBF 方法的推论(图片由作者提供)。
在你的人脸分析项目或应用中,是否使用人脸地标检测作为核心组件?你是否使用流行的计算机视觉库中的人脸对齐方法,如OpenCV【1】或Dlib【2】?如果你想改进你的人脸对齐模型,在这篇文章中,我将解释如何使它们更快、更平滑、更小、更准确、更健壮,特别是对于人脸跟踪应用。此外,我在我的 Gitlab 知识库中提供了一组已经为 OpenCV 和 Dlib 改进的模型,该知识库是为我们在实时图像处理杂志 (Springer)上发表的文章而创建的:
Alvarez Casado,c .,Bordallo Lopez,M.
实时人脸对齐:评估方法、训练策略和实现优化。
施普林格实时图像处理杂志,2021 年
ace 对齐在大多数人脸分析系统中是一个至关重要的组件。它着重于识别图像或视频中人脸的几个关键点的位置。尽管在流行的计算机视觉库中,如 OpenCV 或 Dlib 中,有几种方法和模型可供开发人员使用,但他们仍然面临着照明不足、极端头部姿势或遮挡等挑战,特别是当他们受到实时应用需求的限制时。
如前所述,我们最近发表了一篇期刊文章,其中我们提出了一套基于数据增强和软件优化技术的最佳训练策略和实施规则,这些规则有助于改进属于几个用于人脸对齐的实时算法的各种模型。我们将它们命名为一般培训扩展 ( GTX )策略。此外,我们还提出了一组扩展的评估指标,允许新的评估来缓解在实时跟踪上下文和真实场景中发现的典型问题。实验结果表明,使用我们提出的技术生成的模型更快、更小、更准确,在特定的挑战性条件下更鲁棒,在跟踪系统中更平滑,如下一个视频所示。
这种训练策略显示出适用于不同类型的设备和算法,使它们在学术和工业应用中通用。
为了评估我们的方法,我们专注于三种被认为是不同应用的最先进的人脸对齐方法, LBF (局部二进制特征)[3]用于 OpenCV , ERT (回归树的集合)[4]用于 Dlib 和 DAN (深度对齐网络)[5],可在 pip (Python)中获得。LBF 和 ERT 方法,也称为快速人脸对齐方法,基于级联回归器,而 DAN 算法基于深度学习方法。我们使用由多饼地标方案定义的 68 个地标位置。
评估度量和基准 面部对齐的标准度量通常包括那些与基础事实注释相比时与预测质量相关的度量。这主要包括准确度和误差,在某些情况下还有失败率。此外,通常计算计算效率,通常以每个面的毫秒数表示,以及每秒处理的帧数(fps)。
问题在于,这些度量没有测量在大多数面部对齐模型中观察到的若干现象,例如:
- 抖动:恼人的帧间噪声和微小变化。这种影响可能是由缺乏训练样本、具有高方差的不精确注释、不干净的数据集或者在例如初始化阶段使用某种(伪)随机信息的非确定性推理方法产生的。
- 人脸对齐灵敏度:大部分人脸对齐算法依赖人脸检测包围盒进行形状初始化。面部检测器在连续的帧中并不总是一致的。此外,大多数人脸对齐模型是用一个人脸检测器的人脸矩形来训练的。
基于这些现象,我们定义了三个新颖的度量,并使用它们来评估一个模型在跟踪应用期间有多好的性能。我们建议计算两个连续帧估计形状之间的帧间误差:
- 地标均方位移度量(laMSD),计算地标在静态人脸下如何沿视频移动。
- 归一化抖动灵敏度均方误差 (NJS-MSE_σ )是通过使用基于水平和垂直轴上的小中心偏移的面部矩形的随机变化来推断一组参考图像上的面部标志而计算的度量。误差测量产生评估度量,以比较面部对准模型的 抖动鲁棒性 。
- 归一化人脸检测灵敏度均方误差 (NFDS-MSE_σ )。对于此度量,随机变化基于水平和垂直轴上的面部矩形中心偏移以及面部边界框的大小(宽度和高度)的随机变化。这产生了一个评估度量,用于比较我们的面部对准模型与 不同面部检测器 的鲁棒性。
为了评估我们的模型,我们在文献中先前提出的完善的标准基准和我们精心设计的一组基准的组合中测试它们。大多数相关工作主要关注两个性能指标,准确度和效率,但我们认为它们不是评价人脸对齐模型的唯一关键指标。我们相信这种基准组合有助于描述在无约束环境下运行的实时应用程序中更加客观和现实的行为。这些基准描述如下:
- 野外常见的 基准(300-W)【6】,用以测试一般精度和误差作为与其他机型比较的参考。
- 抖动基准,重点测量模型的抖动效果
- 特定领域基准,侧重于测试特定领域的模型,如弱光条件、极端倾斜的头部、强背光场景等
训练策略
主要思想是实现“更好”的人脸对齐模型。传统上,这是指更精确的模型。但如前所述,我们通过评估实时应用和真实场景中的其他关键方面,特别是在跟踪地标时,扩展了这一概念。
为了实现这一目标,我们建议在培训过程中执行几条规则,例如:
- 基于图像处理的数据扩充:几何和颜色变换。
- 基于统计操作的数据扩充:图像归一化、噪声注入、初始化变化、异常值去除。
- 添加领域特定数据:我们研究属于已证明在基本模型中失败的特定条件的图像集合。这些图像用一个缓慢而精确的模型和一个教师
学生建筑来注释。在我们之前的出版物中可以看到关于这项技术的更多细节。
实现和并行化
我们已经描述了从串行优化到并行化策略的一系列实现技术。从性能及其可能的精度折衷的角度分析了这些解决方案。
为了测试这些建议的优化,我们实现了自己的 C++版本的 LBF 方法。因此,我们可以将我们自己的实现与 OpenCV 实现进行比较,例如相同的算法,并在 OpenCV 和 Dlib 的实现版本中执行一些其他优化。
在文章中,我们解释了如何加快训练和推理过程。在训练中,我们通常使用OpenMP【7】来加速算法拓扑允许的循环。更准确地说,我们在 LBF 算法中加速了局部特征映射函数的学习,因为如图 1 所示,每个界标都是独立于其余的。
图。1(图片由作者提供):LBF 方法中的训练过程。学习过程遵循级联式拓扑。局部特征的线性回归最小化当前形状和目标地面真实形状之间的距离。
在训练我们的面部对齐模型之后,我们通过主要应用三种策略来加速推断:
- 每个地标计算的并行化(局部特征映射功能)。
- 加速在上述过程中提取的高维特征和全局线性回归或转移矩阵 w 的相乘。我们应用三种不同的优化技术,如图 2 所示。
- 对生成的模型进行量化。我们将模型的数据从浮点数转换成短整数。这提高了推断的速度,尤其是在具有缓存和内存限制的设备上,例如移动设备。
图 2(图片由作者提供):稀疏线性投影 W t 的乘法,在面部对齐
过程的每个阶段使用 3 种不同的技术计算。
对比评估
为了更好地理解之前的规则集以改进我们的人脸对齐模型,我们从误差、模型大小、计算时间以及跟踪模式和挑战场景中的性能等方面,对最终模型中的训练策略和实现优化技术的影响进行了实证评估和分析。作为 GTX 训练策略的结果,我们获得了一组被标记为 LBF_gtx 模型的增强模型,这些模型将与 LBF_base 模型和其他互补模型进行比较。
精度与尺寸和速度对比:
300 瓦全套测试的平均误差(%)和失败图像(%)。在中间一栏中,每个型号的大小以兆字节(MB)为单位。在上一栏中,基准测试中的平均计算时间是以每张脸毫秒数为单位的。在评估的 LBF 模型中,“q”表示量化模型,“float”是原始模型,它们都已经集成到我们的 C++管道中。DAN 模型是原始论文中提供的原始模型。并且通过 Dlib 库使用 ERT 模型,比较库提供的模型和我们自己训练的 ERT 模型。OpenCV LBF 模型通过 OpenCV 库使用。索引 1、2、3 和 4 表示 OpenCV 默认模型与不同的人脸检测器一起使用,包括板载的哈尔卡斯卡德人脸检测器和 DNN 人脸检测器。该推断是使用配备 2.6 GHz 英特尔酷睿 i7 处理器的笔记本电脑做出的(图片由作者提供)。
我们的抖动基准测试中的抖动评估:
在我们自行设计的抖动基准测试中,总抖动量和每帧抖动量按每帧 laMSD 增长排序。该推断是使用配备 2.6 GHz 英特尔酷睿 i7 处理器的笔记本电脑得出的。我们的 LBF 模型是浮动版本,以便与 OpenCV one(图片由作者提供)进行公平的比较。
特定于领域的性能指标评测:
在使用领域特定的未标记数据和师生方案训练基础模型之后,在 300W 全套和领域特定的测试子集上的平均误差(%)和失败图像(%)(图片由作者提供)。
模型量化的影响:
对于不同的
硬件设备,量化在准确性(300 w-公共数据集)、速度和大小方面的影响(图片由作者提供)。
定性结果
为了查看建议的培训策略和实施优化的影响,我创建了一些视频来观察它们的效果。
结论
本文的结果显示了一组优化和训练策略在人脸对齐系统环境中的影响,该人脸对齐系统旨在集成到在台式计算机和移动设备中实时运行的解决方案中。在没有任何算法开发的情况下,我们展示了训练、实施和系统设计的巧妙策略如何在准确性、速度、模型大小或挑战性条件下的失败率方面对模型的性能产生巨大影响。
感谢阅读。我希望你从阅读这篇文章中学到的和我写这篇文章时学到的一样多。干杯!
这项工作与 米盖尔·博尔达洛 合作完成。
- 奥卢大学助理教授兼讲师 Miguel Bordallo López 博士。https://sites.google.com/view/miguelbordallo
更多详情请见:
Alvarez Casado,c .,Bordallo Lopez,M.
实时人脸对齐:评估方法、训练策略和实现优化。
施普林格实时图像处理杂志,2021
从以下位置下载模型: 从文章的 GitLab 资源库中下载代码、模型、基准数据集和示例视频,文章中生成的模型现在是 Dlib 库模型库中的标准模型。
- 我们的 LBF_gtx 和 ERT_gtx 车型:我们的车型
- 原始和默认 OpenCV LBF 模型: OpenCV LBF 模型
- 原丹型号:丹型号
- 原始和默认 Dlib ERT 模型: Dlib ERT 模型
参考文献
[1] OpenCV 库:
【2】Dlib 库:
【3】s . Ren,X. Cao,Y. Wei,J. Sun,“通过回归局部二值特征实现 3000 FPS 的人脸对齐”, 2014 年 IEEE 计算机视觉和模式识别会议,美国俄亥俄州哥伦布市,2014 年,第 1685–1692 页,doi: 10.1109/CVPR.2014 “使用回归树集合的一毫秒人脸对齐”, 2014 年 IEEE 计算机视觉和模式识别会议,美国俄亥俄州哥伦布,2014 年,第 1867-1874 页,doi:10.1109/cvpr . 2014.241 .
[5]m . Kowalski,J. Naruniec 和 T. Trzcinski,“深度对齐网络:用于鲁棒人脸对齐的卷积神经网络”, 2017 年 “野外 300 人面临的挑战:数据库和结果”。图像和视觉计算(IMAVIS),面部标志定位“野外”特刊。2016.
【7】OpenMP 库:https://www.openmp.org/
更快的 Spark 查询,两者兼得:Python 和 Scala
当 Spark SQL 和 Python UDFs 太慢时,如何使用 Scala 和 PySpark 实现高级 Spark 用例
由Unsplash【CC0】拍摄的图像
S park 是大数据时代的黄金标准和主力。几乎所有数据科学家和数据工程师都依赖 Spark 来处理日常数据工作负载。但是这两个用户群之间有一个典型的分界线:
- 许多数据工程师使用 Scala 和类型化数据集 API 编写 Spark 作业,而
- 大多数数据科学家使用 PySpark 和无类型 Spark 数据帧。
Python 是迄今为止数据社区中最受欢迎的语言,Spark 自早期以来取得了长足的进步,统一数据集 API、Arrow、Spark SQL 和矢量化 Pandas UDFs 使 PySpark 用户在使用 Spark 时成为一等公民。
[OC]
您可能正在阅读这篇博文,因为您有一些高级用例,其中实现是 Scala,类型化数据集 API 将是有益的。
- 共享代码库,例如,数据科学家想要重用来自数据工程管道的一些复杂的业务逻辑
- 您需要实现复杂的业务逻辑,并希望使用 Scala 强大的集合和方法
- 您希望使用复杂的自定义类型,因为您的数据不太适合表格数据模型
- 你必须处理组合问题、嵌套循环和大数组,你的 Spark 工人会因为 OOM 错误而死
这只是我多年来在使用 Scala 和类型化数据集 API 时遇到的几个例子,至少是在 PySpark 管道的一部分中。好消息是,您不必用 Scala 培训所有的数据科学家,也不必重写他们所有的 PySpark 工作流。PySpark 只是一个 API,所有的 PySpark 工作流最终都在 JVM 上的 Spark 中运行。这使得我们可以在同一个 Spark 管道中轻松混合和匹配 Python 和 Scala。
下面的例子演示了如何使用一些业务逻辑为每个输入行创建大量的输出行。当然,您可以在 PySpark 中解决这个问题:
def getBigList() -> List[int]:
return [random.randint(1, 999999) for x in range(10000)]bigListUdf = udf(
getBigList,
ArrayType(IntegerType())
).asNondeterministic()spark.createDataFrame([
Row(cid='cid1'),
Row(cid='cid2'),
Row(cid='cid3')
]).select(
'cid', explode(bigListUdf()).alias('sku')
).join(
productDf, ['sku']
)
但是传递一个大的列表并将其分解成大量的新行需要您的节点为这一阶段的这一步留有足够的内存余量。这是一个简单的例子,但是您甚至可能再次过滤掉许多新行,因为它们与您的整个管道不相关。在您的真实世界用例中,您甚至可能有列表列表等。我们如何通过使用类型化数据集来改进这一点呢?
[合理使用]
flatMap
类型化数据集转换相当于 Dataframes 的explode()
方法,重要的是可以使用迭代器。这消除了在内存中实现列表的需要。你可能还记得 Python 2 的【https://www.geeksforgeeks.org/range-vs-xrange-python/】,你可以阅读这篇关于生成器优势的文章:
数据工程师可能会将您的 PySpark 代码翻译成某种 Scala 版本,生成带有Iterator
和flatMap
的新行
package business_logiccase class InputData(cid: String)
case class OutputData(cid: String, sku: String)object BusinessLogic {
private def generateSkus(cid: String): Iterator[OutputData] = ??? def getCidSku(df: DataFrame): DataFrame = {
import spark.implicits._
val ds = df.as[InputData]
ds
.flatMap( x => generateSkus(x.cid) )
.toDF
}}
scala 代码被数据工程师编译打包成一个jar
文件。
数据科学家只需将罐子添加到他们的 Spark 会话中
spark = (
SparkSession.builder
.config("spark.jars.packages", "business-logic_2.12-1.0.0.jar")
.getOrCreate()
)
我们希望在使用非类型化数据帧的 PySpark 管道中使用类型化数据集来使用这部分业务逻辑。
from pyspark.sql import SparkSession, DataFramespark = SparkSession.builder.getOrCreate()
sc = spark._sc
sqlContext = spark._wrappedcid_df = spark.createDataFrame([
Row(cid='cid1'),
Row(cid='cid2'),
Row(cid='cid3')
])cid_sku_df = DataFrame(
sc._jvm.business_logic.BusinessLogic.getCidSku(cid_df._jdf),
sqlContext
)cid_sku_df.join(
productDf, ['sku']
)
这不是最令人难忘的语法,但这是您如何从 PySpark 调用任何 Java/Scala 代码来完成 Spark 工作负载,并打破使用 Spark 和 PySpark 的团队之间的语言障碍。
Spark 数据集的 Scala API 文档:https://Spark . Apache . org/Docs/latest/API/Scala/org/Apache/Spark/SQL/Dataset . html
为什么不阅读下一篇文章,了解如何使用 PEX 打包 PySpark 应用程序用于生产—相当于 Python 的 Spark 和 assembly JARs:
Jan 是公司数据转型方面的成功思想领袖和顾问,拥有将数据科学大规模应用于商业生产的记录。他最近被 dataIQ 评为英国 100 位最具影响力的数据和分析从业者之一。
在 LinkedIn 上连接:https://www.linkedin.com/in/janteichmann/
阅读其他文章:【https://medium.com/@jan.teichmann】T21
FasterAI:制作更小更快的神经网络的库
理解大数据
FasterAI 包括一组用于神经网络的压缩技术,构建于 Fastai 和 Pytorch 之上
作者图片
FasterAI 简介
→图书馆可以在这里找到https://github.com/nathanhubens/fasterai
FasterAI 是一个项目,它通过使用 fastai 库来使神经网络变得更小更快。这里实现的技术可以很容易地与普通 Pytorch 一起使用,但是我们的想法是以一种抽象和易于使用的方式来表达它们( à la fastai)。
在本文中,我们将通过一个用例来解释如何使用 FasterAI。
准备好了吗?那我们开始吧!
为了演示的目的,让我们先了解一些背景知识。假设我们想要在存储容量有限的移动设备上部署一个 VGG16 模型,并且我们的任务要求我们的模型运行足够快。众所周知,参数和速度效率不是 VGG16 的强项,但让我们看看我们能做些什么。
我们先来检查一下 VGG16 的参数个数和推断时间。
*learn = Learner(dls, vgg16_bn(num_classes=10), metrics=accuracy)*
因此,VGG16 有 1.34 亿个参数
*Total parameters : 134,309,962*
并花费 4.03 ms 对单幅图像进行推断。
*4.03 ms ± 18.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)*
啪!这超出了我们的部署能力,理想情况下,我们希望我们的模型只需要一半的容量…但是我们应该放弃吗?不,实际上有很多技术可以帮助我们减小模型的尺寸并提高速度!让我们看看如何用 FasterAI 应用它们。
我们将首先训练我们的 VGG16 模型,以便对它的性能有一个基准。
*learn.fit_one_cycle(10, 1e-4)epoch | train_loss | valid_loss | accuracy | time
0 | 2.016354 | 1.778865 | 0.3689170| 1:31
1 | 1.777570 | 1.508860 | 0.5235670| 1:31
2 | 1.436139 | 1.421571 | 0.5691720| 1:32
3 | 1.275864 | 1.118840 | 0.6300640| 1:31
4 | 1.136620 | 0.994999 | 0.6878980| 1:31
5 | 0.970474 | 0.824344 | 0.7396180| 1:31
6 | 0.878756 | 0.764273 | 0.7656050| 1:32
7 | 0.817084 | 0.710727 | 0.7819110| 1:31
8 | 0.716041 | 0.625853 | 0.8048410| 1:31
9 | 0.668815 | 0.605727 | 0.8109550| 1:31*
因此,我们希望我们的网络具有相当的精度,但参数更少,运行速度更快……我们将展示如何使用的第一项技术叫做知识蒸馏
知识蒸馏
知识提炼是一种简单但非常有效的训练模型的方法。卡鲁阿纳等人于 2006 年推出了这一技术。背后的主要思想是用一个小模型(称为学生)来近似一个更大的高性能模型(称为老师)所学的函数。这可以通过使用大模型来伪标记数据来实现。这个想法最近已经被用来打破 ImageNet 上最先进的精确度。
当我们训练模型进行分类时,我们通常使用 softmax 作为最后一层。这个 softmax 的特点是将低值逻辑值挤向 0,将最高值逻辑值挤向 1。这实际上完全丢失了所有的类间信息,或者有时被称为黑暗知识。这是有价值的信息,我们希望从老师那里传递给学生。
为此,我们仍然使用常规分类损失,但同时,我们将使用另一个损失,在老师的软化逻辑(我们的软标签)和学生的软化逻辑(我们的软预测)之间计算。这些软值是在使用 soft-softmax 时获得的,这样可以避免在其输出端挤压这些值。我们的实施遵循本文,培训的基本原则如下图所示:
作者图片
要在 FasterAI 中使用知识蒸馏,您只需在训练学生模型时使用此回调函数:
**KnowledgeDistillation(student, teacher)**
你只需要给回调函数你的学生学习者和你的教师学习者。在幕后,FasterAI 将使用知识精华来制作您的火车模型。
首先要做的是找到一个老师,可以是任何模型,最好表现良好。我们将选择 VGG19 进行演示。为了确保它比我们的 VGG16 模型性能更好,让我们从预训练版本开始。
*teacher = cnn_learner(dls, vgg19_bn, metrics=accuracy)
teacher.fit_one_cycle(3, 1e-4)epoch | train_loss | valid_loss | accuracy | time
0 | 0.249884 | 0.088749 | 0.9727390| 1:02
1 | 0.201829 | 0.087495 | 0.9742680| 1:02
2 | 0.261882 | 0.082631 | 0.9740130| 1:02*
我们的老师有 97.4%的准确率,这已经很不错了,它已经准备好保护学生了。因此,让我们创建我们的学生模型,并通过知识蒸馏回拨对其进行培训:
*student = Learner(dls, vgg16_bn(num_classes=10), metrics=accuracy)
student.fit_one_cycle(10, 1e-4, cbs=KnowledgeDistillation(student, teacher))epoch | train_loss | valid_loss | accuracy | time
0 | 2.323744 | 2.102873 | 0.4109550| 2:16
1 | 2.099557 | 2.441147 | 0.5714650| 2:16
2 | 1.829197 | 2.215419 | 0.6076430| 2:16
3 | 1.617705 | 1.683477 | 0.6670060| 2:16
4 | 1.364808 | 1.366435 | 0.7133760| 2:16
5 | 1.257906 | 0.985063 | 0.7880250| 2:16
6 | 1.087404 | 0.877424 | 0.8010190| 2:16
7 | 0.949960 | 0.777630 | 0.8221660| 2:16
8 | 0.868683 | 0.733206 | 0.8377070| 2:16
9 | 0.756630 | 0.707806 | 0.8430570| 2:16*
我们可以看到,老师的知识确实对学生有用,因为它明显超出了基线 VGG16。
好了,现在我们能够从一个给定的模型中得到更多,这有点酷!通过一些实验,我们可以设计出比 VGG16 更小的模型,但能够达到与我们的基线相同的性能!您可以稍后尝试自己找到它,但现在让我们继续下一项技术!
稀疏化
现在我们有了一个比基线表现更好的学生模型,我们有一些空间来压缩它。我们将从稀疏网络开始。
注 :通常情况下,使网络稀疏的过程称为剪枝。当参数实际上从网络中移除时,我们更喜欢使用术语修剪,这将在下一节中进行。
在 FasterAI 中,稀疏化过程也是通过使用回调来管理的,回调将在训练期间用零替换模型中最不重要的参数。回调函数有各种各样的参数来调整您的稀疏化操作,让我们来看看它们:
**SparsifyCallback(sparsity, granularity, method, criteria, sched_func)**
- 稀疏度:你想要的网络稀疏度的百分比
- 粒度:你希望在什么粒度上进行稀疏化操作(
weight
、kernel
、filter
、…) - 方法:无论是
local
还是global
,都会影响参数的选择,是在每一层单独选择(local
)还是在整个网络上选择(global
)。 - 标准:用于选择移除哪些参数的标准(
large_final
、movement
、…) - sched_func :你希望按照哪个调度进行稀疏化(目前支持:fastai的任意调度函数,即
annealing_linear
,annealing_cos
,...而且还有经典的时间表如one_shot
、iterative
、annealing_gradual
、朱古普塔&提出的时间表
但是让我们回到我们的例子上来!
这里,我们将使我们的网络 40%稀疏,并删除整个过滤器,本地选择并基于 L1 规范。我们将以稍小的学习率进行训练,以温和地对待我们的网络,因为它已经被训练过了。所选择的调度是一个退火余弦,所以修剪开始和结束都很温和。
*student.fit(10, 1e-5, callbacks=[SparsifyCallback(40, granularity='filter', method='local', criteria=large_final, sched_func=annealing_cos)])Pruning of filter until a sparsity of 40%epoch | train_loss | valid_loss | accuracy | time
0 | 0.584072 | 0.532074 | 0.8384710| 1:31
1 | 0.583805 | 0.499353 | 0.8445860| 1:31
2 | 0.599410 | 0.527805 | 0.8364330| 1:32
3 | 0.610081 | 0.544566 | 0.8280250| 1:31
4 | 0.625637 | 0.543279 | 0.8298090| 1:31
5 | 0.628777 | 0.563051 | 0.8196180| 1:31
6 | 0.688617 | 0.617627 | 0.8000000| 1:32
7 | 0.691044 | 0.629927 | 0.8010190| 1:31
8 | 0.669935 | 0.576220 | 0.8140130| 1:31
9 | 0.682428 | 0.562718 | 0.8239490| 1:31Sparsity at epoch 0: 0.98%
Sparsity at epoch 1: 3.83%
Sparsity at epoch 2: 8.25%
Sparsity at epoch 3: 13.83%
Sparsity at epoch 4: 20.01%
Sparsity at epoch 5: 26.19%
Sparsity at epoch 6: 31.76%
Sparsity at epoch 7: 36.19%
Sparsity at epoch 8: 39.02%
Sparsity at epoch 9: 40.00%
Final Sparsity: 40.00*
我们的网络现在有 40%的滤波器完全由零组成,代价是 2%的精度。显然,选择较高的稀疏度会使网络更难保持类似的精度。其他参数也可以广泛地改变我们的稀疏化过程的行为。例如,选择更细粒度的稀疏性通常会导致更好的结果,但在速度方面更难利用。
我们可以仔细检查我们的模型确实被修剪了 40%的参数。
*Sparsity in Conv2d 2: 39.06%
Sparsity in Conv2d 5: 39.06%
Sparsity in Conv2d 9: 39.84%
Sparsity in Conv2d 12: 39.84%
Sparsity in Conv2d 16: 39.84%
Sparsity in Conv2d 19: 39.84%
Sparsity in Conv2d 22: 39.84%
Sparsity in Conv2d 26: 39.84%
Sparsity in Conv2d 29: 39.84%
Sparsity in Conv2d 32: 39.84%
Sparsity in Conv2d 36: 39.84%
Sparsity in Conv2d 39: 39.84%
Sparsity in Conv2d 42: 39.84%*
我们没有确切的 40%,因为当我们去掉完整的过滤器时,我们不一定有一个整数。
现在让我们看看我们在速度方面获得了多少。因为我们删除了 40%的卷积滤波器,我们应该期待疯狂的加速,对不对?
*4.02 ms ± 5.77 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)*
实际上,没有。我们没有删除任何参数,我们只是用零代替了一些,记得吗?参数的数量仍然相同:
*Total parameters : 134,309,962*
这将引导我们进入下一部分。
修剪
重要提示:这目前仅支持全前馈模型,如 VGG 模型,因为更复杂的架构需要越来越困难且通常依赖于模型的实现。
为什么我们没有看到任何加速度,即使我们去掉了一半的参数?这是因为我们的 GPU 本身不知道我们的矩阵是稀疏的,因此无法加速计算。最简单的办法,就是用物理地移除我们归零的参数。但是这种操作需要改变网络的架构。当移除层 i+1,中的过滤器时,它也影响层 i+2,中的内核,因为它们现在变得无用并且可以被移除。
作者图片
这种修剪只有在我们事先将整个滤波器归零的情况下才有效,因为这是唯一可以相应地改变架构的情况。希望稀疏计算很快能在普通深度学习图书馆中可用,所以这一部分在未来将变得无用,但目前,这是我们能想到的最好的解决方案🤷
这是 fasterai 的样子:
*pruner = Pruner()
pruned_model = pruner.prune_model(learn.model)*
您只需传递其过滤器已被稀疏化的模型,FasterAI 将负责移除它们。
注意 :该操作应该是无损的,因为它只移除已经不再参与网络的过滤器。
在我们的例子中,它给出了:
*pruner = Pruner()
pruned_model = pruner.prune_model(student.model)*
现在,让我们看看我们的模型能够做些什么:
*Total parameters : 83,975,344*
就速度而言:
*2.44 ms ± 3.51 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)*
耶!现在我们可以说话了!让我们再次检查我们的准确性没有改变,我们没有在某个地方出错:
*Loss: 0.5641388, Accuracy: 0.8229*
实际上我们还能做更多的事情!让我们继续前进!
批量标准化折叠
批量规范化折叠是一个非常容易实现和简单的想法。要点是批量标准化只不过是对每一层的输入数据进行标准化。此外,在推断时,用于这种标准化的批次统计是固定的。因此,我们可以通过改变卷积的权重将归一化过程直接合并到卷积中,并完全移除批量归一化层,这在参数和计算方面都是一个增益。更深入的解释,请看我的上一篇帖子。
这是如何与 FasterAI 一起使用:
*bn_folder = BN_Folder()
bn_folder.fold(learn.model))*
注意 :该操作也应该是无损的,因为它重新定义了卷积以考虑批量范数,因此是等价的。
让我们用我们的模型来做吧!
*folded_model = bn_folder.fold(pruned_learner.model)*
参数下降通常不太明显,尤其是在 VGG 这样的网络中,几乎所有参数都包含在 FC 层中,但是,任何增益都是值得的。
*Total parameters : 83,970,260*
既然我们删除了批处理规范化层,我们应该再次看到加速。
*2.27 ms ± 1.22 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)*
再一次,让我们仔细检查我们没有在某个地方搞砸:
*Loss: 0.5641388, Accuracy: 0.8229*
我们还没完成呢!正如我们所知,对于 VGG16,大部分参数都包含在全连接层中,因此我们应该对此有所作为,对吗?
FC 层因子分解
事实上,我们可以分解我们的大的全连接层,并用两个更小的近似层来代替它们。其思路是对权重矩阵进行 SVD 分解,将原矩阵表示为 3 个矩阵的乘积:uσVT。其中σ是沿其对角线具有非负值的对角矩阵(奇异值)。然后,我们定义奇异值的值 k 来保持和修改矩阵 U 和 VT 。结果将是初始矩阵的近似值。
作者图片
在 FasterAI 中,要分解模型的全连接层,您需要执行以下操作:
*FCD = FCDecomposer()
decomposed_model = FCD.decompose(model, percent_removed)*
*percent_removed*
对应去除奇异值的百分比( k 值)。
注 :这次分解不确切,所以我们预计之后业绩会下降,需要进一步的再培训。
在我们的示例中,如果我们只想保留其中的一半:
**fc_dec = FCDecomposer()
dec_model = fc_dec.decompose(folded_model, percent_removed=0.5)**
我们现在有多少参数?
**Total parameters : 61,430,022**
我们赢得了多少时间?
**2.11 ms ± 462 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)**
然而,这种技术是近似的,所以它不是无损的,所以我们应该重新训练我们的网络来恢复它的性能。
**final_learner = Learner(data, dec_model, metrics=[accuracy])
final_learner.fit_one_cycle(5, 1e-5)epoch | train_loss | valid_loss | accuracy | time
0 | 0.795416 | 0.759886 | 0.7729940| 0:51
1 | 0.752566 | 0.701141 | 0.7943950| 0:51
2 | 0.700373 | 0.650178 | 0.8048410| 0:52
3 | 0.604264 | 0.606801 | 0.8216560| 0:51
4 | 0.545705 | 0.592318 | 0.8231850| 0:51**
这种操作通常对较新的架构用处不大,因为它们的全连接层中通常没有那么多参数。
概括地说,我们在本文中看到了如何使用 FasterAI 来:
- 让学生模型向教师模型学习(知识蒸馏)
- 使我们的网络稀疏化(稀疏化)
- 可选地,物理移除零滤波器(修剪)
- 移除批量定额层(批量规格化折叠)
- 用较小的层来近似我们的大的全连接层(全连接层因式分解)
我们看到,通过应用这些,我们可以将 VGG16 模型的参数从 134 百万减少到 61 百万,并且还可以将推断从 4.03 毫秒加速到 2.11 毫秒,与基线相比,准确性没有任何下降(甚至实际上略有增加)。
当然,这些技术可以与量化或混合精度训练结合使用,Pytorch 中已经提供了这些技术,可以进行更多的压缩和加速。
注意 :请记住,上面介绍的技术不是神奇的🧙♂️,所以不要期望每次都能看到 200%的加速和压缩。您能实现什么在很大程度上取决于您正在使用的架构(有些已经通过设计实现了速度/参数效率)或它正在执行的任务(有些数据集非常简单,您可以删除几乎所有网络而不会看到性能下降)
仅此而已!感谢您的阅读,我希望您会喜欢 FasterAI。我不认为它是完美的,你可能会发现很多错误。如果你有,请告诉我,我可以试着解决它们😌
计算出版物 h 指数的最快方法
一个简单而优雅的算法胜过许多导出 h-index 的普通方法
摄影: Jonathan Chng 在 Unsplash
最初由 J.E .赫希提出,作者的 h 指数被认为是他们学术成就的可靠指标。在一个普通的学术术语中,h-index 指的是最高的数字“h ”,这样作者就有 h 篇论文被至少 h 次引用。媒体社区的成员可以这样解释:这是一个最大的数字“h ”,一个作者写了至少 h 篇博客,收到了至少 h 个掌声。
让我们用一个例子来理解这个概念。一个作者发表了五篇博客(或研究文章),收到了以下掌声(引用):【10,1,5,3,15】。h 指数是 3,因为至少有三个博客至少有 3 次鼓掌。另一位作家可能收到了[100,2,1,1,1]个掌声,h 指数只有 2。虽然它不是衡量一个人写作和学术能力的完美标准,但据称它在大多数情况下都能很好地反映一个作者的整体写作质量。
h 指数的假设应用
假设有许多多产的作家,他们每个人都发表了数百篇关于 Medium.com 的各种主题的博客文章,包括其所有的姐妹出版物。自然,对于每个作家来说,有些文章比其他文章更受欢迎(以获得的掌声来衡量)。现在,编辑希望根据他们的 h 指数来衡量他们的表现,并相应地奖励最具生产力和质量的作家——作家的 h 指数值越高,奖励越大。
现在,编辑要求我们编写最快的程序来计算 h 指数。在集思广益会议和快速互联网搜索后,我们确定了四种不同的方法来得出 h 指数,如下所述:
- For-loop(我们的想法)
- 数字广播(我们的想法)
- Python 包(别人的想法)
- 好的算法(别人的想法)
接下来的部分将更详细地解释这四种方法,并计算它们在我们的测试用例中的性能。
For 循环
在许多情况下,涉及一个或多个 for 循环的计算在计算上是低效的,然而它们仍然是最直观和最容易的做事方式。在理解 for 循环计算之前,让我们引入一个新的术语 k-index,它指的是任何 k,使得 k 篇文章有 k 次引用。k 的最大值是 h-index,这意味着一个作者可以有多个 k-index,但只有一个 h-index。h-index 的默认值为零,并且不能大于文章数。
基于 for 循环的 h 索引代码如下所示。for 循环技术通过在一个范围内从 1 到文章总数依次迭代来寻找所有可能的 k 索引。k 的最高值被认为是给定引用数组的 h 指数。
在代码中,我已经确保通过“中断”两个循环,只执行必要的计算。在第一个循环中,一旦发现 h 篇文章有 h 个引用,循环就停止迭代其余的值。第二个循环只持续到下一个 h 小于前一个值的点,这表明我们找到了最大 h。
注意:我尝试了非优化(无中断)的循环,效率极低,所以我将其从结果中排除。
数组运算
意识到 for 循环固有的缓慢,我们决定执行数组操作。我们可以用 Numpy 广播操作替换内部和外部 for 循环以及相关的 if 语句。数组允许我们同时确定所有的 k,而不是逐个计算 k 指数。下面分享代码块。
Scholarmetrics 软件包
我们已经在网上搜索了是否存在计算 h 指数的标准 Python 包,正如我们所知,总是有 Python 库可用。Michael Rose 写的【Scholarmetrics 软件包及其代码分享如下。请注意,稍微修改过的代码版本(方法 2)使用了 Numpy sum,而不是 Python 的内置 sum 函数。
资料来源:基于迈克尔·E·罗斯编写的学校计量学软件包 GitHub 代码
专家算法
我们还在其他地方寻找,发现一些专家已经提出了一个简单的算法来推导 h 指数。该算法按逆序(降序)对引文进行排序,并按升序将其与相应的整数序列进行比较。两条曲线交点处的整数值就是我们的答案,编码如下:
确认
在我们比较这四种解决方案之前,我们需要确保它们能产生相同的结果。因此,我们可以随机生成一个样本并验证这三种方法:
上面的代码产生以下结果。所有技术都给出相同的输出,我们知道这是正确的,这验证了我们的代码。因此,我们现在可以继续进行比较测试了。
比较
所有实验运行重复三次,每次重复运行 100 次,并以秒为单位记录时间。正如 Python 文档推荐的那样,我们只使用了最短的运行时间。结果如下所示:
作者图片
正如所料,专家算法表现出最佳性能,其次是 Python 包代码。有趣的是,我们在 Scholarmetrics 包中使用 np.sum()而不是 sum()提高了速度,表现几乎与最佳技术相同。
令人惊讶的是,随着大小的增加,for-loop 比数组操作做得更好。这是因为即使我们消除了 for 循环,我们还是进行了计算。没有 if 语句来减少冗余步骤,代码必须处理整个输入数组。
最后的想法
在这篇博客中,我们研究了计算 h 指数的不同方法的计算效率。有三点要记住。首先,高效的算法是无可替代的。其次,精心编写的 for 循环也能以可接受的速度执行。第三,在 Numpy 数组上使用 Numpy 函数比使用内置 Python 函数更快。
全周期数据科学(FCDS)
行业笔记
扩展数据驱动型组织的关键
在当今世界,没有数据的行动仅仅是一种观点,一个运行良好的数据科学部门不仅仅是“有就好”,而是业务繁荣的一个强烈要求。
然而,如何让一个数据科学部门取得成功并没有单一的秘诀。
虽然许多不同的公式可能适用于小型/直觉驱动/发展中的组织,但随着组织的成长和成熟,真正的问题(以及对解决方案的需求)开始显现。
如今,找到一个可扩展的解决方案是几乎所有值得尊敬的科技公司都面临的难题。
鉴于这一组织问题的本质以及某种程度上的哲学问题,我鼓励读者在他们的组织和需求发生变化时,重新审视这一问题及其首选解决方案。
在我的职业生涯中,我遇到过很多解决数据驱动的规模问题的方法。见鬼,我亲自尝试了至少一半…我很高兴地宣布,我确实找到了一个我爱上了的食谱,我觉得它足够有效,值得分享。我写这篇文章是想告诉你关于它的事情,我的经历,为什么我认为它很棒,以及给那些想在他们的组织中认真评估/实施它的读者一些建议。
为了使这个配方可重复,它需要被很好地记录和命名(这篇文章和所说的)。
为了描述它,我创造了一个术语全周期数据科学 (FCDS),我认为这是对它所包含的内容的恰当描述(下文将详细介绍)。
简而言之,FCDS 是一种生活方式,使单个数据从业者能够结束整个产品生命周期,独立交付端到端产品,只关注它们带来附加值的地方。
达成这个解决方案,包括实现它的理念和技术,是许多同事@Waze & @Google 的团队努力。我很幸运能和这些专业的、以成功为导向的人一起工作,这促进了实验,直到找到这个解决方案。
在本文中,我将宣称这不仅仅是扩展数据驱动型业务的一种功能性方法,而且是迄今为止最有效的方法。
这篇文章代表我自己(丹尼尔·马科斯)的个人信念,与某个特定的组织无关。因此,它非常固执己见。我对自己热衷的事情非常有主见,这是其中之一:)
希望这个食谱和它的想法能引起一些读者的共鸣。如果你最终采纳了其中的一些,那么绝对值得花时间写下来!请不要客气,这样我们就可以交流从难以捉摸的道路到规模的战斗故事。
问题是
定义成功
我是一名数据科学家。作为其中一员,我无法在没有明确定义 KPI 的情况下解决问题。我在这里要展示的东西是否真的可以测量还有待商榷,但我会尽力而为。
那么,我们实际上如何定义一个成功的数据科学单位呢?为了想出一个扩展的方法,我们首先需要定义成功是什么样子。
领导期望通常有些模糊(非常令人惊讶……),但听起来常常像这样—
一个成功的数据[科学]部门应该为决策提供信息,并转变我们经营业务的方式。
这些可以是微观的(例如交易层面)或宏观的(例如我们应该把增长集中在哪里?)级别的决策,这里唯一重要的是它们是数据驱动的,或者像有些人喜欢说的那样是“智能的”。
让我们试着将它分解成业务 KPI(或者对我们的数据组织来说是 OKR )。
一个成功且可扩展的数据科学部门应该针对以下方面进行优化:
- 业务影响 —我们生产的工件(无论是模型、分析、洞察力、报告、仪表板、演示)转化为影响我们业务的可衡量的结果。
这些结果可以表现为战略和决策制定指导(通常称为“数据科学洞察”),也可以表现为直接优化 KPI,如给定改进模型的收入(例如欺诈检测、CTR 预测)。 - 速度 —洞察时间(无论是决策、新业务洞察还是生产就绪型 ML 模型)应尽可能缩短。这里没有经验法则,这在很大程度上取决于项目的性质,但底线是——不要因为效率低下而行动迟缓,从而阻碍产品的决策。
- 质量——通知和指导决策是一项重大责任。基于仔细审查的干净数据的准确、可理解的见解对于质量决策至关重要。没有比产生见解、让企业根据这些见解采取行动、然后才意识到自己的见解是错误的更好的摧毁数据单位可信度的方法了。有点常识的读者会理直气壮地认为“这是不可避免的”。的确如此,尽管这里的目标是尽量减少这种情况。
你可能已经明白质量&速度是你需要管理的一个权衡。既然你意识到了这一点,你就可以和你的利益相关者讨论这些选项,并做出明智的决定,在这两者之间划一条线(每个项目/产品都不一样)。
衡量这一属性是很棘手的,通常是定量(例如,未解决问题的数量,给定时间范围内产品迭代的数量)和定性(例如,利益相关者调查)的结合 - 可持续发展 —一个成熟的数据驱动型组织会重新评估其成长过程中做出的决策。因此,考虑到新的数据、更新的假设,并且尽可能与之前的决策点相比较,重新考虑这些决策是至关重要的。为了允许这样的工作方式,代码(产生洞察/训练 ML 模型)必须是完全可复制的、自动化的(点击一个按钮就可以重新运行),并且写得很好。可持续产品通常有工件,比如详细的文档,足以让新员工(甚至未来的你)回去,理解它,信任它,调整它,并产生新的结果。
值得注意的是,KPI 的这种构成非常适合数据驱动的业务(“行业”)。对于纯研究和学术数据科学工作来说,情况肯定不是这样(例如,速度-质量权衡优先于质量)。许多成熟的数据组织确实雇用了研究科学家,他们不太受业务驱动,但他们的研究确实与业务目标一致,并最终会对生产产生影响。这些研究人员可能在同一个数据科学部门工作,也可能在不同的部门工作,尽管企业的高层次目标总是优秀的产品、增长和利润。这些目标推动了上述数据科学部门的成功定义。
数据科学生命周期
为了讨论解决方案,我们首先需要稍微了解一下数据科学项目的生命周期。
生命周期是指管理数据科学项目需要采取的步骤及其顺序。
这通常是指主要的项目阶段,如启动/定义、开发/原型、部署&实验和测量。
它有很多种风格,使用不同的命名、序列、ML 规范等等。
在这里讨论一个具体的生命周期是没有意义的,因此我们将只提及一些高级生命周期的重要注意事项:
- 循环 —数据科学的生命周期总是循环的。当处理数据、创建见解/模型,并与利益相关者/实验验证它们时,随着您对数据越来越熟悉,您往往会发现新的问题。这些可能需要更多的数据清理,重复假设、目标、度量等的定义。因此,这个生命周期被视为循环的,您可以随时返回到上一步,从该点继续循环
- 研究 VS 生产 —这个周期通常包括两者。您首先从了解领域开始,尝试不同的方法和原型。有时你甚至不知道在这个阶段你正在尝试做的事情是否可行。当你有一个满意的工件时,你将尝试并“生产化”它——调整并使它可用于你组织的生产基础设施,关注部署、资源、规模、延迟、成本、监控、协调等。
周期中的这两个不同步骤彼此非常不同,在传统组织中需要不同的职能(例如科学家与工程师)和实施。这是我们在这里试图解决的问题的很大一部分。 - 操作 —周期的最后一步,此时您已经有了生产部署的实施,例如生产 ML 模型/实时仪表板/发送给管理层的报告。在这一点上,您需要确保您的工作持续运行——进行测量、监控,并在出现问题时发出警报(例如,数据偏差、概念漂移、异常、性能不佳等)。).忽略这一部分实际上会让你的工作变成“一次性的”。虽然对某些项目有好处,但在生产中/决策中使用一些您无法重现和/或调整和修复的东西是非常危险的,以防以后发现问题(在您的工作中或甚至在您所依赖的数据中,因为显然您很棒,您不会犯错误)。
我个人在某种程度上与这种(面向 ML 的)数据科学生命周期有关。它描述了原型制作本身就是一个循环,我发现这非常正确。
数据科学产品生命周期(图片作者:丹尼尔·马科斯
数据科学挑战
上面提到的多功能循环很难产生有效的、有组织规模的数据工作。
谷歌的论文——机器学习系统中隐藏的技术债务(NIPS 2015)中提出了对这一挑战的补充观点。
用一张图来概括——
机器学习系统中隐藏的技术债务— NIPS 2015 ( 作者图片,丹尼尔·马科斯)
现在来解释一下这幅图:)
这意味着当数据科学家(在这种情况下实施 ML 模型——红框,但让我们稍微概括一下)进行研究时,她只关注产生洞察力的核心——例如模型训练/ KPI 测量(有趣的部分!).问题是,当她想要生产那段代码时,有许多其他“隐藏”的盒子,她现在必须实现并注意将它集成到生产就绪系统中。
TL;DR — 让数据科学家不把大部分时间花在他们带来附加值的地方,是扩展数据驱动型组织的最大敌人。
这样做的挑战在于:
- 速度退化——最佳状态意味着她的研究代码是“立即产生可电离的”,所有其他部分(灰色方框)都是现成的(没有方框双关语)。不幸的是,这种情况并不常见。
- 数据科学家的时间 —上述许多挑战让我们意识到,实际上,一名现实生活中的数据科学家并没有把大部分时间花在她能带来附加值的地方。相反,她经常被拉去做运营和“生产调整”(例如扩展)工作,受到移交的阻碍,最终成为一个效率较低的自己。让数据科学家不把大部分时间花在他们带来附加值的地方,是扩展数据驱动型组织的最大敌人。
- 质量因缺乏重点和极度复杂而受损。
*技能集 —传统的数据科学技能集不包括扩展(软件工程)、自动化和监控(软件可靠性工程师/“devo PS”),有时甚至不包括数据收集(卸载给其他工程师——有史以来最严重的错误……我们稍后会谈到这一点)。
一个极端的情况是,数据科学家的研究代码实际上必须由 SWE(软件工程师)在不同的语言/技术堆栈中实现,以便与生产堆栈一起工作。除了速度,它在很多方面都是危险的!试探法,不同的包做不同的事情,训练服务偏差,等等。 - 可持续发展很难实现,传统上也不被视为一个重要因素。这反过来又通过跳过“非数据”部分,如自动化、再现性、监控、完整文档等,推动了缩短项目时间的愿望。
*维护 —可扩展的数据驱动型产品是为长期发展而构建的,而不是一次性的。这意味着在你“完成”一个项目后,所有这些可怕的灰色方框不会停止向你袭来。记得 cyclic 吗?当警报触发、模型性能下降、数据更改或技术堆栈升级时,数据科学家被召回维护岗位。灰色方框越多,预计维护就越多。 - 业务影响 —获得可行见解(=生产)的时间大大高于进行纯研究的时间。在成熟的组织中,这可能意味着需要不成比例的大量劳动力来支持数据驱动的产品。然而,对于一般的组织来说,基于数据驱动(主要是 ML)的产品通常会失败,花费的时间比预期的要长,或者产生“半生不熟”/“某种智能”的结果。
*移交——几乎是生产力的对立面。不要误解我的意思,我并不是说我或者任何其他人应该承担一切,在没有同事的情况下工作。我想说的是,个人贡献者拥有的越多,生产力就提高得越多,其中最佳的解决方案是拥有整个产品生命周期。将研究工作移交给 SWEs,将自动化工作移交给 SREs,将监控工作移交给 Ops 是对速度和质量的重大打击。
*所有权 —当很多人参与到一个项目的不同阶段时,一种非常微妙的所有权平衡就出现了。我的部分在哪里结束,你的部分在哪里开始?谁拥有整个过程?最终产品?藏物呢。正在做的决定?警报?当数据或假设改变时,再现性和更新?
所有上述问题都受到组织结构(康威定律)等)的显著影响。)但我不打算在本文中深入探讨这一点(我也不打算声称我已经搞清楚了这一部分)。
解决方案
现在,如果我告诉你所有这些挑战都是可以解决的,会怎么样?(或者至少是可优化的)。我在这里提倡的全周期数据科学生活方式就是建议的解决方案。我有意把它称为一种生活方式,因为它由哲学、文化和技术组成。
你为什么要相信我?(你不应该,不要盲目相信你看的任何东西,而是想一想,觉得有意思就试试)。
它经过了战斗的考验。目前为止。)对我和我的同事有效。
这种方法实际上对数据科学家来说很有吸引力,所以说服人们尝试它并不困难——我基本上是在向你承诺更少的繁重工作和更多有趣的东西。
它是通过实验设计出来的。我(个人)犯了书中几乎所有的错误。这些错误确实有助于找出问题并试图提出解决方案。
这些错误表现为:
- 从未进入生产的数据科学/ ML 项目
- 数据科学/ ML 项目在进入生产阶段时遭遇了可怕的失败
- 无效(至少可以这么说)DS:SWE 协作和移交
- 需要为生产“重新编码”——例如,将 python ML 代码翻译成 Java,因为这是后端团队使用的代码。
- 不成比例的维护负荷
如果你认识到以上的一些(或全部),也许这将会引起你的共鸣。
全周期工程是指一个工程师拥有整个产品生命周期。
虽然这个概念对于阅读本文的数据人员来说可能是新的,但听众中的工程师可能已经熟悉了全周期开发人员的概念。这是一个很有趣的想法。
借用数据科学领域的信息技术,创建我们所谓的全周期数据科学 (FCDS)是我们扩展数据科学组织的解决方案。
高效的数据科学家
我们已经定义了成功并认识到挑战。下一步是在我们想要设置的解决方案(FCDS)的背景下,创建我们的高效数据科学家档案。
大概是这样的:
- 专注于你最擅长的事情 —在一个包含多个职能部门(如工程师、科学家、分析师)的大型组织中,当人们将时间集中在能带来最大附加值的地方时,效率会最大化。在软件领域,这意味着关注业务逻辑,而不是样板文件和操作。对于数据科学家来说,“逻辑”部分主要是特征工程和数据操作。利用自己的创造力和领域知识获得正确的数据,思考对要解决的问题有最大影响的特性,并确保它们(或创造性的代理)可供使用。此外,重要的是提出正确的指标、优化方法和实验设计来衡量它们。任何 DS 都会同意,关注数据(质量和丰富性)和度量(例如,优化正确的度量)虽然不那么迷人,但对成功来说比模型本身重要得多。运营不应该是数据科学家的重点,也不应该占用他们大量的时间(请参见下面的“不运营”部分)。
公平地说,通过调用. fit
/.transform
来“训练”模型,甚至使用一个花哨的包来进行 hp 调整,都是非常机械的,与一个刚毕业的学生相比,你并没有增加多少价值。这些是最容易被 AutoML 取代 DS 工作(我是一个大粉丝)的部分,也是最容易根据帕累托原则减少你的努力的部分。在大多数商业(利润驱动)组织中,几乎总是帕累托规则适用的情况,并且 80%的预期交付物和 20%的花费时间足够好,能够做出决策,快速试验并继续下一个项目。这一事实在当今超级数据驱动的世界中更加明显,在这个世界中,数据科学几乎驱动着每一个决策——积压的项目如此之多,以至于很少值得为一个单独的项目超过 80%。 - 独立性 —在一个完美的世界里,单个 DS 个人贡献者(IC)可以独立完成完整的数据科学产品生命周期(参见该名称的来源?).同一 IC 开发并拥有从研究到生产级服务的所有步骤。不仅如此,同样的 IC 只需要关注逻辑而不是 ops!听起来很理想,但很疯狂,对吗?实际上,2021 年并没有那么疯狂。我想提醒的是,产品生命周期并没有在生产中结束,它包括操作、持续监控和验证、定期再培训/重新验证假设等等。你仍然应该拥有所有这些,关键是使它们足够简单,以适应一个标准的 DS 的技能集,并且在努力方面几乎是免费的。
- 不行动:我们说过 DS 不应该碰行动,但是必须有人碰。对吗?监控、编排、部署、扩展、延迟和数据质量管理对于一个健壮的生产系统来说都是至关重要的。然而,对于绝大多数数据科学产品来说,它们看起来非常相似。如今,模型性能监视器、持续培训编排、持续模型部署和数据验证框架都很容易集成(并且几乎是“可复制粘贴的”)。这意味着为您的产品设置它们应该是一个简单的配置问题,或者最好的情况是复制/继承一个现有的配置。这将使一切“免费”设置,但维护呢?这部分等式的关键是连续。持续的培训、数据验证、部署(模型&数据——又名特性存储)对于确保系统健康至关重要。一个持续健康的系统和使用连续操作(CI/CD/CT)快速检测问题是一个成熟的数据系统消除维护负载的方式。
回顾我们使用数据实现业务转型的目标,全周期数据科学理念表明,这可以通过授权、独立、专注的数据科学家来实现。
全周期数据科学
哲学
E
数据科学家通常从定义/界定问题开始,考虑正确的测量和优化功能。这需要很强的业务理解、领域知识和沟通技巧。然后,她开始研究、查阅文献、实验,并尝试不同的方法。这需要以研究为导向的心态、创造力、有条理的方式和扎实的黑客技术(一点点运气不会有坏处)。
开发/生产化包括编码、测试、与生产系统的集成以及对资源的关注。这需要编码技能(显然,其他的也是,但是我们在这里谈论的是产品级)、强大的数据操作和理解以及架构/设计经验。
最后是衡量和运营,需要深入研究、解释和向利益相关者提供服务的能力。
你可以看到拥有完整的周期需要拥有广泛技能的全面数据科学家。
大多数数据从业者都知道,清理数据是 80%的工作。这是周期中非常重要的一部分,如果不是最重要的话,在我们的理念中,这一部分应该永远由数据科学家完全拥有。我怎么强调这有多重要都不为过。
不管你喜欢与否,清理数据是你带来最大附加值的地方。凭借您的领域知识、创造力和商业敏锐度,这对于高性能模型和准确的洞察力来说是最重要的。
作为一名数据科学家,这无疑是你工作时间最长、最重要的一部分。
不,你肯定不太会清理自己的数据。
你是说有一个人比你更合适,就是那个建立模型并负责其性能的人,来决定哪些数据适合过滤/清理以及如何过滤/清理?如果是这样,你可以就此打住,和质量说再见。
值得一提的是,为了让您能够独立地结束循环,不得存在任何类型的重新实现—例如,由 SWE 为生产重新实现的 DS 研究代码。它不仅容易出错,是不好的做法,还增加了依赖性。这意味着你需要从一开始就使用正确的工具。这并不难,只是意味着要留意你使用的技术。如果你不能生产它,它就没用了。
C
它不仅减少了移交,还为数据科学家开启了一个全新的业务影响世界。此外,我发现对于我的同事来说,产品所有权意识是必不可少的。当你按下部署按钮,看到流量增加到你的模型,你会尽一切努力来确保它的质量和健壮性。
在大多数组织中,将代码推向生产是 SWE 的任务,如果你做错了,你可能会造成伤害。此外,它可能需要各种各样的软件/SRE 技术,如 CI/CD,而数据科学家对此一无所知。认为这真的会让你失败。使用正确的工具、托管服务、测试和标准程序来推送代码,可以让一个 5 岁的孩子将代码推向生产,而造成(严重)伤害的风险极小。
生产问题呢?作为一名数据科学家,我现在需要支持调用我的模型的生产服务吗?我需要带着呼机(不是真的)在午夜回复生产问题吗?
是的,你有。
你拥有产品。(不是实际的服务器/网络,只是输出预测的服务)。你是支持它的最佳人选。当你的模型开始输出垃圾时,你是唯一一个知道如何修复它的人(这是会发生的)。
老实说,人们倾向于认为这很可怕,但如果你做得对(像其他事情一样),这很容易。也不一定总是你…这就是为什么随叫随到轮换是一件事。
用一张图来总结哲学(来源):
FCDS 哲学(作者图片,丹尼尔·马科斯)
当前的行业标准要求 X (~3)人将数据产品(例如 ML 模型)投入生产。
FCDS 承诺让一名独立的(全周期)数据科学家独自完成这项工作,更快、更高质量地专注于他们带来附加值的领域。 还有,你看业界 DS 被气的对不对?这是因为他将大部分时间花在了更接近运营的事情上(如扩展和监控),而不是调用 fit_transform(这是他真正喜欢做的事情)。
如果我在这一点上说服了你,但你在想“这在理论上很酷,但没有任何工具可以做到这一点,我不是谷歌/脸书,所以我不能只是去建立一些东西……”那么我有一个惊喜给你。
我们有技术。
技术
我们希望这项技术能够让普通的数据科学家结束产品周期,专注于逻辑,并让其他一切开箱即用。
这种技术的特点是:
- 简单——理解、使用、操作
- 托管 —没有服务器,没有硬件,只有代码
- 可定制的——免费获得简单的东西,但足够灵活,可以为 5%的人疯狂,这需要到外面去
- 可扩展的 —自动可扩展的数据处理、训练、推理
- Pythonic——不要尝试其他东西……我们需要一种生产就绪的东西,它可以与当今大多数工具和代码一起工作,并且适合标准的数据科学家。如今几乎没有其他选择(我已经说过这是固执己见了吗?).
是否存在包含整个数据科学周期的工具?我希望。
但是有许多很棒的工具可以满足上述所有要求,当它们粘在一起时,可以很容易地结束这个循环。
将它们粘合在一起并自动化管道以适应您的组织可能需要一点时间……但这一次的努力是值得的。此外,工具变得越来越好,越来越丰富,正如我们所说的那样,占用了越来越大的周期,所以当你读到这篇文章时,它可能比我必须经历的要容易得多。
在本文的这一点上,值得花一分钟来确保您理解了"全周期"(产品生命周期)!= "全栈"(技术栈——例如后端和前端)
其实完全相反!与全堆栈不同,在全周期中,我们的目标是用单个堆栈结束整个产品生命周期!数据科学家堆栈!
Python(和令人敬畏的托管服务)就是你所需要的一切。
工具的选择完全取决于您,我并不试图说服任何读者选择其中一种。这不仅仅是一个纯技术的问题,而是你的组织喜欢什么,云提供商,个人偏好,对黑暗模式的支持(超级重要)等等。
为了充分披露,我在@Google,Waze 工作,使用 GCP 托管服务(我真的很喜欢)。为了让读者对这样的堆栈有一个大概的了解,我将非常粗略地列出我的 FCDS 堆栈中的几个工具(都是可扩展和可管理的):
- BigQuery:结构化数据存储和 SQL 处理
- tfX
*tensor flow2 . x- TF . transform over data flow:批处理&流处理,特性工程嵌入到 TF 模型中,因此您只需编写一次代码
*开箱即用的组件,用于数据验证、模型分析、模型祝福(与以前的模型版本相比)和部署
- TF . transform over data flow:批处理&流处理,特性工程嵌入到 TF 模型中,因此您只需编写一次代码
- 云 AI 平台(CAIP) ->现在叫顶点 AI
- CAIP 笔记本:研究&探索
- CAIP 工作:培训
- CAIP 机型:高负载&低延迟推断
- CAIP 管道:TFX 即服务
- 更多的小补充超出了本文的范围。举几个例子:Git、Gerrit、Jenkins、通过 Cloud Composer 的气流
帮助数据科学家开始使用新 FCDS 技术的一个常用方法是提供生产就绪、可分叉、经过测试的完整管道模板(从数据探索到持续培训和部署)。我发现它极大地缩短了开发时间并简化了采用。
文化
“走向 FCDS”是数据驱动型组织文化中的一项重大变革。数据科学家不仅只能依靠他们自己(可能有些夸张),他们现在还直接为生产做出贡献!
这几乎总是意味着需要以工程为导向提升数据科学家的技能。
新的数据科学文化现在从坚实的工程文化中借用概念。
它现在发现了升值的价值:
- 代码质量 —我们不构建一次性的,我们构建持久的生产系统
*代码评审
*单元测试
*没有生产代码的笔记本(只是为了原型开发)——关于这个主题已经写了无数的文章。TL;DR 是一个成熟的项目代码,包含。py 文件与。ipynb 文件。它易于重用(可导入)、可测试、可审查、通用、可参数化、可与其他组件集成、不依赖数据等。基本上,它让你走上了可持续发展的正确道路。是的,我知道笔记本领域有几种工具可以尝试解决这些问题。我只想说,你可以给猪涂口红,但它还是一头猪。 - 系统质量 *研究文档&评审
*设计文档 &评审
*成功定义- KPI /测量设计
*实验设计
- KPI /测量设计
实施说明
全周期数据科学家简介
数据科学有多种口味。FCDS 方法足够通用,可以应用于其中的许多领域,可能是机器学习,取代试探法和算法,产品分析或传统统计。通常情况下,数据科学家需要平衡这些不同类型的项目。此外,每一个这样的领域(例如 ML)可能包括非常不同的子领域(例如推荐系统、计算机视觉、NLP)。
这就是为什么我们的方法更喜欢数据科学 通才 (缝针修复)——全面发展的个人,他们可以深入新的领域和工作类型,并应用他们的数据导向、技术技能集和领域知识来创造成功的产品。这些人确实存在,我正在和他们中的一群人一起工作!(作为经理,我的职责是让他们意识到他们有能力做到这一点,并提供一些小的指导)。对于专家来说,您的组织足够大吗?(多面手的反义词)请便,但你可能希望专家成为研究科学家,而不是数据科学家。
我很少见过在生产影响导向的岗位上比多面手做得更好的专家。老实说,对于任何多面手来说,使用现成的 keras 架构/领域 SOTA 模型只需几个小时。
FCDS 以影响力为导向。这意味着像每一个值得尊敬的软件开发哲学一样,我们以敏捷的方式工作。
我们从小处着手,我们制作原型,我们建立一个可靠的生产管道(分叉模板,在几分钟内准备好)并实现一个简单的基线(甚至不一定是一个模型!).我们建立测量,然后我们开始迭代和改进。
现在我将进入真正有争议的部分:)
我们可以将世界分为两种类型的数据科学家——行业驱动型和学术驱动型。
FCDS 非常重视产品影响和代码质量,它倾向于前者。
显然两者兼而有之很好,但是为了说明一点,我要声明比起没有生产经验/糟糕的编码技能的博士,我更喜欢雇佣一个优秀的、思维敏捷的、对数据有兴趣和良好感觉的工程师。
我们之前提到过,独立性对于高效的数据科学家至关重要。然而,重要的是不要把独立和隐居混为一谈。不善于与他人合作的“独狼”类型不是数据科学家的良好形象。独立意味着你可以快速行动,但是集思广益、相互审查以及与利益相关者的密切沟通对于深入研究和数据解释这种工作来说是非常重要的,而这种工作是数据科学家的谋生之道。
总而言之,一个伟大的全周期数据科学家是一个独立、全面的通才,他喜欢什么都做一点,拥有扎实的编码技能,重视敏捷,喜欢生产影响胜过研究。
有效性危险信号
拥抱像 FCDS 这样的新生活方式及其哲学、技术和文化是一个过程。与其指出一大堆要遵循的规则,不如指出清晰的危险信号来表明效率的降低和道路的偏离。
危险信号包括:
- 角色(非常固执己见)
数据工程师做的是构建工具以外的事情。这是我怎么强调其重要性都不为过的头号错误。数据工程师是软件工程师,他们构建恰好在数据领域的软件系统。还记得我们说过,我们需要把一堆不同的工具粘在一起,让每样东西都能为普通的 DS 工作吗?适应我们的组织需求,建立稳固的 CI/CD 渠道等。这都是数据工程。
构建数据管道和仪表板(ETL / BI)是数据科学家的角色。它是周期*的重要组成部分!把它交给别人意味着我们没有完成整个周期。如果你认为有些 ETL 对于 DS 来说太复杂了,你没有使用正确的工具或者没有雇佣正确的数据科学家。
工程师不应该写 ETL (缝合修复)
*你有一个 ETL / BI 工程师角色。同上,这意味着您的 DSs 没有完成整个周期。
*你有一个 ML 工程师的角色。如果你需要一个工程师把你的 ML 代码投入生产,那么你的 DSs 就没有做完整的循环。
*您需要 SREs/Devops 协助将 DS 代码推向生产 - 处理问题
*由用户发现的数据/模型问题,而不是由警报发现的问题
*无法回滚到先前的模型版本
*不容易复制当前的生产模型
*重新训练模型是手动的 - 重新实施
- DS 需要在研究和生产之间重新实施他们自己的工作
- DS 移交研究代码(模型/特征工程等。)供 SWE 重新编码到生产堆栈中
- 错位
*用于分析/训练(离线)的数据与用于生产/推理(在线)的数据不完全相同
*特征工程代码使用试探法/代理来补偿未记录的数据
时机
你可能会问自己,这是否是你的组织尝试采用 FCDS 的正确时机。
答案是肯定的。
- 小型创业公司构建数据组织?以这种方式开始——无论如何你都必须这样做,因为雇佣专家而不是能做所有事情的多面手对你来说是非常昂贵的。你只需要投资合适的工具,让他们的生活更轻松。
- 大公司?这是最难的,因为文化已经存在,人们对自己的所作所为感到满意。但是,这是您将看到对速度、质量和整体业务影响最大的地方。
- 中间的某个地方?在你大到难以改变文化之前,开始尝试这种方法。尝试,慢慢过渡,先只做一些项目,投资科技(反正对你有好处)。开始模糊不同职能之间的界限,让 DS 慢慢地从 DE/SWE/SRE 身上咬下一大块,直到你可以结束这个循环。
摘要
扩展数据驱动型组织的最有效方法是采用全周期数据科学,这是一种端到端的方法,其中个人结束整个产品周期,专注于他们带来附加值的地方,并获得其他现成的东西。
这种方法应该创建一个成功的数据组织
- 速度 * DS 可以专注于创意方面
*可重用组件和可复制粘贴的生产就绪模板 - 质量 * DS 清理自己的数据
*现成的数据验证&监控 - 可持续性 *自动化
*可再生
*可扩展 - 业务影响 *可操作洞察/生产最小化的时间
*单个 DS 完全端到端独立- DS 拥有生产产品&工件
*满意度 ** DS 关心生产
** DS 感受他们的影响
- DS 拥有生产产品&工件
那么,扩展数据驱动型组织的问题解决了吗?大概不会。我已经在 2020 年左右开始了这项工作,现在效果很好,但那只是在我们遇到下一组问题之前。此外,整齐地结束循环所需的一些工具甚至还没有出现…这些天来,可扩展的训练推理服务的部署很容易找到,但当涉及到功能存储和“数据部署”时,它仍然是一个大烂摊子。
我要感谢我的许多同事@Waze & @Google ,他们通过实验、集思广益、提出问题和不断努力把事情做得更好,为这项工作做出了巨大贡献。
我也要感谢 Alon Palombo 和 Philippe Adjiman 对这部作品的详细回顾和贡献。
fd:一个简单但功能强大的工具,用于在命令行中查找和执行文件
找到任何文件。很简单。快点。
动机
你有没有想过不用离开终端就能找到文件?find
允许你这样做,但是它的语法很复杂。
如果您可以使用如下的简单语法来搜索文件,那不是很好吗?
作者图片
这就是 fd 派上用场的时候。在本文中,我将向您展示什么是 fd,以及如何使用它来快速查找任何文件。
什么是 fd?
fd 让你快速找到任何文件。fd 相比find
更容易上手。下面是两个命令之间的比较。
作者图片
换句话说,你只需要用fd pattern
搜索带有pattern
的文件。
装置
按照本说明书安装 fd。
其他有用的功能
查找具有特定文件扩展名的文件
如果您想查找具有某种文件扩展名的文件,如.md
或.py
,请使用fd -e extension_name
。
作者图片
使用正则表达式
您也可以使用正则表达式来查找如下文件:
作者图片
在特定路径中查找文件
如果你想找到某个目录下的文件,只需使用fd PATTERN directory_name
。
作者图片
命令执行
有时你可能想抓取多个文件,然后对它们做些什么。这也可以用 fd 来完成。要对每个搜索结果执行命令,将-x
添加到命令中。
您可以尝试使用此功能做一些有用的事情:
- 移除以
txt
结尾的文件
作者图片
- 在您喜欢的编辑器中打开多个文件
作者图片
- 重命名多个文件
作者图片
注意{}
是搜索结果的占位符(text1.txt
、text2.txt
)。
{.}
也是搜索结果的占位符,但没有文件扩展名(text1
、text2
)。
高级功能
忽略大小写
默认情况下,fd 区分大小写。可以添加-i
忽略大小写。
作者图片
将目录遍历限制到给定的深度
默认情况下,搜索深度没有限制。通过在命令中添加-d
,可以将目录遍历限制在给定的深度。
作者图片
在命令中添加-d 1
告诉 fd 只搜索当前目录中的文件。
查找隐藏文件
fd 的另一个强大功能是显示隐藏文件,比如.git
。要查看隐藏文件,在命令中添加-H
。
作者图片
忽略文件
您还可以通过在命令中添加-E
来忽略特定的文件
作者图片
…或者将您想要忽略的文件添加到同一目录下的.fdignore
文件中:
作者图片
很酷,不是吗?
要查找 fd 提供的其他功能,请键入:
fd --help
结论
恭喜你!您刚刚学习了如何找到具有特定模式的文件,并使用 fd 执行它们。我希望这个工具能把你从花在小任务上的时间中解放出来,这样你就可以腾出时间来做重要的任务。
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以在 LinkedIn 和 Twitter 上联系我。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
💔-tools-to-track-and-visualize-the-execution-of-your-python-code-666a153e435e>
功能选择和公平性:少即是多
公平和偏见
深思熟虑的预测值选择对于模型的公平性至关重要
我经常听到的一个常见的与人工智能有关的担忧是,机器学习模型将利用隐藏在庞大的个人信息数据库中的古怪事实来做出影响生活的决定。例如,你在简历中使用 Arial 字体的事实,加上你养猫和喜欢 pierogi,会阻止你得到一份工作。与这种担忧相关的是害怕由于这种推断而受到基于性别或种族的歧视。这种恐惧是愚蠢的还是现实的?机器学习模型是基于相关性的,任何与一个结果相关联的特征都可以作为决策依据;有理由担心。然而,这种情况发生的风险取决于模型可用的信息和所使用的特定算法。在这里,我将使用样本数据来说明随机森林与 XGBoost 模型中纳入附带信息的差异,并讨论在评估模型公平性时考虑缺失信息、适当性和因果关系的重要性。
特征选择——检查可能缺少的和包含的——对于模型的公平性非常重要。通常特征包含仅仅被认为是保留或省略了“敏感”特征,如种族或性别,或这些特征的显而易见的代理。然而,模型可以利用与结果相关联的任何特征,并且模型性能和公平性的通用度量将基本上不受影响。偶然的相关特征可能不是合适的决策基础,或者它们可能代表不公平的风险。当模型中不包括适当的预测因子时,附带特征风险最高。因此,仔细考虑可能遗漏的内容至关重要。
资料组
本文基于上一篇博文的结果,并使用相同的数据集和代码库来说明缺失和附带特性的影响[1,2]。简而言之,我使用一个公开可用的贷款数据集,其中的结果是贷款违约状态(二元),预测因素包括收入、就业时间、债务负担等。我倾向于(但随机地)将低收入案例归为虚构的“女性”类别,为了简单起见,只考虑两种性别类别(“男性”和“女性”)。结果是“女性”的平均收入较低,但男性和女性的收入重叠;有些女性收入高,有些男性收入低。通过检查常见的公平性和绩效指标,我发现无论模型是依靠收入还是性别来预测违约,结果都是相似的,这说明了仅依靠指标来检测偏差的风险。
我之前的博文展示了当一个附带特性代替了一个合适的特性时会发生什么。在这里,我将讨论当适当的预测因子和附带特征都包含在数据中时会发生什么。我测试了两种类型的模型,并表明,正如所料,女性身份有助于预测,尽管它不包含额外的信息。然而,偶然特征对随机森林模型的贡献比对 XGBoost 模型的贡献大得多,这表明模型选择可能有助于减少不公平风险,尽管应该考虑权衡。
公平指标和全球重要性
在我的示例中,女性特性没有向已经包含收入的模型添加任何信息。任何对女性身份的依赖都是不必要的,并代表着“直接歧视”的风险。理想情况下,机器学习算法会忽略这样的特征,而支持更强的预测器。
当随机森林或 XGBoost 模型增加了女性地位这一附带特征时,我发现总体性能特征或性能指标几乎没有变化(数据未显示)。ROC 分数几乎没有变化(这是意料之中的)。假阳性率显示非常轻微的变化。
当纳入女性指标时,XGBoost 的人口统计均等(即女性与男性的贷款违约率差异)基本保持不变(5.2%比 5.3%),但对于 random forest,该指标从 4.3%变为 5.0%;我将在下面详细讨论这个观察结果。
对于两种模型类型,全局排列重要性显示出女性特征的微弱影响。这个特性在随机森林模型中排名 12/14,在 XGBoost 中排名 22/26(当女性=1 时)。女性地位相对较低的事实似乎令人放心,但这一特征的任何影响都是公平风险。
当数据中包含女性地位时,全球指标中没有明确的危险信号,但这是意料之中的,因为无论决策是基于偶然因素还是因果因素,公平指标都是相似的[1]。关键问题是:纳入女性地位是否会增加结果的差异?
聚合 Shapley 值
我们可以使用聚集的 Shapley 值来衡量某个特征对群体预测差异的贡献程度[3]。这项技术将预测结果率的差异分布在各个特征之间,这样我们就可以确定是什么导致了女性与男性之间的差异。计算包括构建由随机选择的雄性组成的参考数据集,使用该“箔”计算随机选择的雌性的 Shapley 特征重要性,然后合计雌性 Shapley 值(也称为“phi”值)。
下面显示了带有和不带有“女性”特征的两种模型类型的结果。不包括女性的模型的前 5 个特征与包括该特征的模型的女性状态一起绘制。其他所有特征都被总结为“其他”。
显示随机森林(左)和 XGBoost(右)模型中女性与男性预测总体差异相关特征的聚合 Shapley 图。排除(红色条)和包括(蓝色条)女性状态特征的模型的结果包括在内。图片作者。
首先,请注意,对于 random forest 来说,雌性的蓝色条(只存在于包含雌性状态的模型中)比 XGBoost 大得多。条形图大小表示归因于某一特征的女性与男性的概率差异量。对于 random forest,女性状态功能使女性相对于男性的违约概率增加了 1.6%,相比之下,XGBoost 的违约概率为 0.3%,相差约 5 倍。
对于 random forest,女性地位在决定男性与女性预测差异的三大影响特征中排名第一,尽管该特征在全球范围内排名第 12 位。全局重要性没有捕捉到该特征对公平性的影响。
如上一节所述,随机森林模型显示,当模型中包括女性地位时,人口统计均等性下降。这种效应在 Shapley 图中也很明显——女性柱的增加不会被其他柱的减少所补偿。对于 XGBoost 来说,女性地位的微小贡献似乎被其他特征贡献的微小减少所抵消。
当我们考虑算法如何工作时,与随机森林相比,XGBoost 附带特性的影响减少是有意义的。随机森林使用要素的随机子集创建树,并对其进行最佳分割检查。这些初始特征集中的一些将包括附带特征,但不包括适当的预测器,在这种情况下,可以选择附带特征用于分割。对于 XGBoost 模型,分割标准基于对以前模型的改进。偶然特征不能改善基于更强预测器的模型;因此,在几轮之后,我们期望树只包括适当的预测器。
考虑到模型建立机制,也可以理解随机森林的人口奇偶减少。当在随机森林中生成要考虑进行分割的要素子集时,我们基本上有两个“收入”要素,因此更有可能选择(直接或间接)收入信息。
随机森林模型有效地使用了比 XGBoost 更大的功能集。尽管在某种程度上这两种模型类型中都可能出现大量的特性,但是 XGBoost 解决方案将倾向于更少的更具预测性的特性。这降低了但并没有消除与 XGBoost 附带特性相关的风险。
XGBoost 比随机森林公平吗?
在之前的博客文章[4]中,我展示了通过整合交互来减轻特性偏差对于 XGBoost 比对于 random forest 更有效(对于一个测试场景)。在这里,我观察到 XGBoost 模型也较少受到附带信息的影响。这是否意味着出于公平的原因,我们应该更喜欢 XGBoost?
当偶然和适当的特征都包含在数据中时,XGBoost 具有优势,但是当仅包含偶然特征时,XGBoost 不会降低风险。随机森林模型对大量要素的依赖可能是一种优势,尤其是当附加要素与缺失的预测因子相关时。
此外,XGBoost 不太依赖附带特性的事实并不意味着它完全没有贡献。可能只有少数决定是基于不适当的信息。
抛开公平性不谈,随机森林对你可能认为的“解决方案空间”的更大部分进行采样,并依赖更多的预测器,这一事实可能对模型的稳健性有一些好处。当模型被部署并面临数据中的意外错误时,随机森林模型可能更能弥补这一点。(另一方面,如果随机森林包含受错误影响的相关功能,它可能会受到损害,而 XGBoost 模型不会受到影响)。
XGBoost 可能有一些公平性优势,但是“最公平”的模型类型是依赖于上下文的,并且还必须考虑健壮性和准确性。我觉得公平性测试和可解释性,以及深思熟虑的特性选择,在促进公平性方面可能比模型类型更有价值。
我错过了什么?
在选择可能影响生活的模型的特征时,公平性考虑是至关重要的。存在许多现有的特征选择方法,这些方法通常优化准确度或预测能力,但是不考虑公平性。这些没有解决的一个问题是“我遗漏了什么特性?”
一个依赖于偶然特征的模型可能看起来表现合理,尽管做出了不公平的决定[1]。因此,问自己“缺少了什么”是非常重要的建立模型时。这个问题的答案可能涉及主题专业知识或额外的研究。被认为有因果关系的缺失预测因子可能是特别重要的考虑因素[5,6]。
显然,对于一个缺失的预测器,最好的解决方案是合并它。有时候,这可能是不可能的。有些效果无法测量或无法获得。但是你我都知道简单的不可用性很少决定最终的特性集。相反,通常是“信息在不同的数据库中,我不知道如何访问它”,或者“该来源由不同的团队所有,他们很难合作”,或者“我们可以获得它,但需要支付许可费”。功能选择通常反映了时间和精力——这通常是好的。有可能的时候,权宜之计是伟大的。但是,当便利性损害了公平时,确实需要做出一些让步。这时,可能需要公平性测试、聚合 Shapley 图和主题专业知识来进行额外工作或延迟时间表,以确保做出适当的决策。
我包括什么?
另一个关键问题是“我包括了什么?”,这通常可以重述为“这是什么的代理?”这个问题可以简单地应用于数据集中的每一个要素,但是对于被识别为导致组差异的要素,应该非常仔细地考虑;这些特征可以用聚集的 Shapley 图或单独的解释来识别。调查这些特征是否提供了比其他预测因素更多的信息可能是有用的
我像谁,他们以前做过什么?
预测贷款违约、购买产品的可能性或工作成功的二元分类模型本质上是在问这样一个问题:“我像谁,他们以前做过什么?”这里的“like”一词指的是数据中包含的特征的相似值,根据它们对模型的预测贡献进行加权。然后,我们模拟(或近似)该群组在过去所做的事情,以生成一个概率分数,我们认为该分数是该群组中的人的未来结果的指示。
“我像谁?”这个问题触及了人们担忧的核心,即如果人们吃了太多的意大利馅饼,养了太多的猫,或者只是碰巧是某个种族、性别或民族,就会受到评判。令人担忧的是,不考虑总体人口的平均结果,只根据个人在这些群体中的成员资格来评估他们是不公平的。什么是合适的在很大程度上取决于具体情况——也许在心脏病发作模型中考虑精神病患者没什么问题,但在刑事司法环境中就令人担忧了。
我们的模型将人们分组——即使模型是连续的,我们也可以认为这是非常小的桶的极限——然后我们估计这些人群的风险。这与老派的精算表没有太大的不同,只是我们可能会使用非常大的功能集来确定组边界,并且我们可能不会完全意识到我们在这个过程中使用的信息的意义。
最后的想法
功能选择不仅仅是一个数学练习,可能需要主题专家、合规分析师甚至公众的判断。数据科学家对这一过程的贡献应该包括对人群使用可解释技术,并发现驱动群体差异的特征。我们还可以识别高危人群,并询问与结果有因果关系的已知特征。
法律和法规遵从性部门通常关注所包含的功能,他们关注的可能主要是特定类型的敏感信息。考虑模型中缺少的东西并不常见。然而,问题是,“缺少了什么?”至少和“那里有什么”一样重要在确认模型作出公平和适当的决定。
数据科学家可能斗志昂扬,擅长用有限或嘈杂的数据制作模型。从不太理想的信息中得到一个“有效”的模型是令人满意的。承认有些事情做不到可能很难,但有时公平决定了我们现在所拥有的真的不够——或者还不够。
参考
[1] V. Carey,公平指标不会将你从刻板印象中拯救出来 (2020),走向数据科学。
[2]诉凯里。GitHub 资源库,https://github.com/vla6/Stereotyping_ROCDS
[3] S. Lundberg,, (2020),向数据科学解释公平的措施。
[4] V. Carey,如何修正特征偏差 (2021),走向数据科学。
[5] M. Prosperi,Y. Guo,M. Sperrin,J.S. Koopman,J.S. Min,X. He,S. Rich,M. Wang,即和 J. Bian,机器学习中的因果推理和反事实预测,用于可操作的医疗保健 (2020),自然机器智能 2:369–375。
[6]b . schlkopf,机器学习的因果关系 (2019),arXiv:1911.10500v2 [cs .LG】。
特征工程 A-Z
由 Unsplash 上的hkon grim stad拍摄的照片
转换特征以提高模型性能的清单
特征工程是转换数据以提取有价值信息的过程。事实上,如果适当转换,特征工程甚至可以在模型性能中发挥比超参数调整更大的作用。
尽管功能工程有着巨大的作用,但初学者和有经验的数据科学家通常不太理解,有时甚至会误解。最近我问了几个人,他们所说的特征工程是什么意思。有趣的是,他们无法超越缺失值、特征缩放或对数变换。但是当然,这是一个包括各种工具、技术和应用的主题。
在这篇文章中,我把通过特征转换和工程来提高模型性能的许多不同方法放在一起并加以综合。
在进入特征工程之前,我们先来区分一下数据清理。重命名列、更改数据类型(例如,从“对象”更改为“类别”)、将数据分成训练集和测试集—这些都是数据科学项目的重要组成部分,但它们不是功能工程。你可以称之为数据清理。
那特征工程到底是什么?
我将特征工程分为 6 大类:
- 特征抽出
- 特征合成
- 特征转换
- 异常值处理
- 缺失值处理
- 其他(例如多项式变换)
让我们一个一个地了解一下。
特征抽出
假设我们有某种关于消费统计的数据,上面有一个时间戳:
带有时间戳的数据
在本例中,“日期”列可以轻松地用于提取附加特征并生成强大的洞察力,例如工作日、周末或一年中特定时间的消费变化(参见下面的黄色突出显示)。
数据与特征工程
特征合成
特征合成与特征提取相反。在这种情况下,将一个或多个要素组合起来创建新要素,这些新要素比单独创建的要素信息量更大。
比方说,在一个房价数据集中,你有两列:楼层空间(平方英尺)和总房价(美元)。您可以在分析中单独使用它们,但也可以创建一个名为price _ per _ sqft(US $/sqft)的新计算要素。
特征缩放
特征缩放/变换是指在数据预处理中应用的各种方法,用于将数据重新缩放或归一化到不同的范围。缩放的目的是以这样一种方式转换数据,即它们或者是无量纲的和/或具有相似的分布。三种流行的缩放方法是:
a)重新调整:也称为“最小-最大归一化”,这是所有方法中最简单的方法,计算如下:
b)均值归一化:该方法在转换过程中使用观察值的均值:
c)标准化:也称为 Z 分数标准化,这种技术使用 Z 分数或“标准分数”进行特征缩放。它广泛用于机器学习算法,如 SVM 和逻辑回归:
d) Log 变换:在对数变换中,一个特征的每个值都是从 x 变换到 log(x)的。对数变换的一个常见应用是构建线性回归模型,其中连续变量的分布被更改为高斯形式,以满足建模假设。
对数转换受欢迎的另一个原因是因为增加了视觉可解释性和外观,尤其是高方差数据(见下图)。
显示使用和不使用对数变换时面积和人口之间关系的散点图。来源:维基百科。
特征编码
特征编码是指将特征的分类字符串值转换为数字值。
例如,如果您的数据集中有一个“性别”列,并且值表示为女性和男性,您可以将这些字符串转换为数字表示,例如男性= 1,女性= 2。这种编码特征的方式被称为标签编码。
当然,进行标签编码意味着算法可能会对女性(= 2)值赋予比男性(= 1)值更高的权重。为了克服这种情况,人们转而使用 One Hot Encoding 来创建虚拟变量,其中每个类别变成一个虚拟列,值变成 1 或 0。
下面是一个示例,其中一键编码应用于具有分类要素的数据集:
import seaborn as sns
df = sns.load_dataset('tips')
df.head()
没有假人的分类特征
现在在pandas
中创建假人:
import pandas
pd.get_dummies(df)
转换成虚拟变量的分类特征
异常值处理
每个数据科学家都不得不面对他们项目中的异常问题,没有多少例外。离群值是特定于领域和上下文的。如果您正在构建一个模型来预测一个平均价格为 30 万美元的社区的房价,而您的数据集却有一所售价为 1000 万美元的房子,那么这一定是一个异常值。同样,如果一栋房子卖了 3 万美元,你也不希望它出现在模型中。
那么你有什么选择来改变这些离群值呢?以下是您的选择:
- 如果它们仅仅在可接受的范围之外,您可以将它们留在数据集中
- 如果负担得起,您可以删除观察值(例如,您的数据集相当大)
- 封顶/剪裁异常值,将异常值剪裁到某个范围(例如,四分位间距、IQR)。
缺失值处理
缺失值在大多数数据集中很常见,它们被记录为NA
或NaN
。处理缺失数据没有单一的标准方法,人们根据数据集采取不同的方法。这里有 3 种最受欢迎的方法:
- 删除:如果数据集很大,并且缺失发生的次数相对较少,则删除带有缺失值的完整记录。
- 替代/插补:缺失值通常由适当的替代值替代,如列平均值、中位数、最近邻平均值、移动平均值等。
- 统计插补:这是一种复杂的插补方法,使用线性回归作为数据集中其他列的函数来预测缺失值。
其他类型的特征工程
除了我刚刚描述的,在特征工程领域还有一些其他的工作,包括:
- 减少类别数量:对类别特征进行重新分类,即减少类别数量。例如,如果一列中有 6 个教育水平类别,您可能希望将它们分成 3 个类别。
- 宁滨:为数字变量创建区间,例如,“年龄”可以分为< 20、20–30、30–40 等。而不是让它们变成 1,2,3,4 ……40 等。
- 多项式拟合:在回归分析中,除了采用
*y = b0+ b1x*
形式的线性模型,还可以采用*y = b0 + b1x + b2x²*
形式的多项式函数进行拟合,以找到更好的拟合。
摘要
总之,特征工程的主要目的是提取额外的数据/信息以获得更好的模型性能。进行特征工程有许多不同的方法,但最常用的方法是特征提取、特征合成、缩放、异常值处理、缺失值处理、宁滨、多项式变换等。
在这篇文章中,我总结了它们,但是当然,每一个都有很多深入的内容。但是希望我在这里描述的内容可以作为一个有用的参考。如果我错过了什么,你觉得其他的也应该包括进来,请在评论区写下来。
感谢阅读。请随意订阅以获得我即将发布的文章的通知,或者通过 Twitter 或 LinkedIn 与我联系。
特征工程示例:宁滨分类特征
如何使用 NumPy 或 Pandas 快速绑定分类特征
出于机器学习(ML)目的使用分类数据有时会出现棘手的问题。最终,这些特征需要以某种方式进行数字编码,以便 ML 算法可以实际处理它们。
您还需要考虑其他方法来为分类要素建模做好准备。例如,您的模型性能可能受益于宁滨分类特征。这实质上意味着将多个类别归入一个类别。通过应用领域知识,您可以设计新的类别和功能,更好地表示数据结构。
在这篇文章中,我们将简要介绍为什么宁滨分类特征是有益的。然后,我们将通过使用 NumPy 和 Pandas 的具体示例,介绍宁滨分类特征的三种不同方法。
为什么要分类?
对于分类特征,您可能会遇到稀有标签的问题,即在您的数据集中极不常见的类别/组。这个问题通常与基数高的特性有关——换句话说,就是许多不同的类别。
有太多的类别,尤其是很少的类别,会导致一个嘈杂的数据集。ML 算法可能难以穿过这种噪声并从数据中更有意义的信号中学习。
如果你选择一个热编码你的分类特征,高基数也会加剧维数灾难。如果原始变量有 50 个不同的类别,那么基本上就是向数据集添加了 49 列。
类别太多也会导致训练和测试模型时出现问题。一个类别完全有可能出现在测试集中,而不是在训练集中。您的模型将不知道如何处理该类别,因为它以前从未“见过”它。
解决这些问题的一个方法是设计类别更少的新功能。这可以通过将多个类别宁滨(分组)为一个类别来实现。
在下面的例子中,我们将利用关于选民人口统计和参与的信息来探索和设计来自数据集的特征。我选择了 3 个分类变量:
party_cd
:登记选民的政党背景voting_method
:登记选民如何在选举中投票birth_state
:美国注册选民出生的州或地区
数据框前 5 行的屏幕截图—作者提供的图片
如果您想开始将这些方法应用到您自己的项目中,您只需要确保您已经安装了 NumPy 和 Pandas,然后导入它们。
使用 np.where()绑定类别
首先,我们来看看我为什么选择party_cd
。下图显示了每个政党有多少个人选民。
Seaborn countplot 显示了按政党划分的选民分布情况—按作者划分的图像
注册的自由主义者、立宪主义者和绿党成员如此之少,以至于我们在图表上几乎看不到他们。这些是稀有标签的好例子。出于本文的目的,我们将罕见标签定义为占观察值不到 5%的标签。这是定义稀有标签的一个常见阈值,但最终这取决于您的判断。
让我们来看看实际数字的细分:
属于每个政党的登记选民的原始计数和百分比——图片由作者提供
这三类人各占不到总人口的 5%。即使我们把他们都归为一类,这个新的类别也只能代表不到 1%的选民。
“REP”和“DEM”代表两大政党,而“UNA”代表登记为与某个政党无关的选民。因此,在这里,将我们的三个罕见标签归入无党派团体是有意义的,这样我们就有三个类别:两个主要政党各一个,第三个代表选择不与任何一个主要政党结盟的个人。
这可以用np.where()
很容易地完成,它有 3 个参数:
- 一种状况
- 如果满足条件,返回什么
- 如果不满足条件,返回什么
下面的代码使用np.where()
从原始的party_cd
变量创建了一个新的特性party_grp
:
它检查的条件是原始值是否在列表['REP', 'DEM']
中。如果是,那么np.where()
简单地返回原始的当事人代码(尽管我已经把它作为标题案例返回了,因为我个人讨厌看到全是大写的东西)。如果原始交易方代码不在该列表中,np.where()
返回“其他”。我们新设计的party_grp
功能现在更加平衡,没有任何罕见的标签:
属于每个政党的登记选民的原始计数和百分比——图片由作者提供
使用 map()将类别映射到新组
接下来,我们来看看voting_method
的分布:
Seaborn countplot 按投票方法显示选民分布情况-图片由作者提供
不是最漂亮的图表,但我们得到了图片。我们有 8 种不同的投票方式。我大胆猜测,其中一半符合我们对稀有标签的定义。
通过每种方法投票的注册选民的原始计数和百分比-图片由作者提供
没错。我们的类别中有四个是稀有标签。现在,我们可以将它们全部归入“其他”类别,然后就到此为止,但这可能不是最合适的方法。
根据我对这些方法如何编码的研究,我知道“缺席”意味着有人提前投票。因此,我们可以将任何“缺席”方法归入“早期”类别,将“亲自”和“路边”归入“选举日”类别,将“不投票”作为自己的类别,将“临时”和“转移”归入“其他”类别。
下面的代码通过首先使用原始的voting_method
类别作为键定义一个字典来完成这个任务。每个键的值就是我们实际想要的新类别。
最后一行基于voting_method
列中的原始值创建了一个新列vote_method_cat
。它通过将 Pandas 的map()
方法应用于原始列,并输入我们的vote_method_map
来将键转换为相应的值。
通过每种方法投票的注册选民的原始计数和百分比-图片由作者提供
现在,我们已经摆脱了除了我们的一个罕见的标签。最终,我选择放弃那 733 张“其他”票。投票方式实际上是我试图预测的目标变量,我真正感兴趣的是人们如何选择投票。临时选票和转移选票更多地反映了投票的过程和规则,但我的问题具体涉及选民的主动选择。
因此,您不仅可以考虑工程预测特性来更好地表示数据的底层结构,还可以考虑如何最好地表示与您的特定问题相关的目标变量。
使用 apply()应用自定义函数
最后,我们将研究宁滨。这个变量有 57 个类别:每个州一个,缺失信息一个,每个美国领土一个,最后一个类别是在美国以外出生的个人。
所以这张图表看起来滑稽可怕:
Seaborn countplot 显示了按出生地划分的选民分布情况——图片由作者提供
如果您在探索分类特征时看到过这样的图表,这是一个很好的迹象,表明如果您打算将宁滨变量用作模型中的一个特征,您应该将其考虑在内。
以下是 15 种最常见的birth_state
分类:
按出生地统计的原始选民数量和登记选民比例——按作者分类的图片
北卡罗来纳州是最常见的州,这是有意义的,因为该数据是针对北卡罗来纳州特定县的选民的。然后我们会看到很多缺失的值。纽约人和在美国以外出生的人也构成了相当大的一部分人口。基于我们的定义,剩余的 53 个类别是罕见的标签,并将在我们的建模工作中引入大量噪声。
让我们按照美国人口普查地区(东北部、南部、中西部、西部)对各州进行分组。我们还会将出生在美国境内或境外的人归入“其他”组,并将“失踪”作为一个单独的类别。
我们将通过定义我们自己的自定义函数来实现从州到地区的转换,然后将该函数应用于我们的原始变量以获得我们的新特性。有一种方法可以让你编写一个函数来检查每个州并返回想要的地区/类别:
现在用熊猫的apply()
方法来创造我们的新功能:
按出生地统计的原始选民数量和登记选民比例——按作者分类的图片
好多了!我们已经从总共 57 个有 53 个稀有标签的类别减少到只有 6 个仍然有很多意义的类别,其中只有一个符合我们对稀有标签的定义。我们可以考虑额外的分组,但你明白了。
概括一下
我们涵盖了:
- 绑定分类特征意味着什么
- 为什么以及何时需要绑定分类特征
- 宁滨分类特征的 3 种方法(
np.where()
、熊猫map()
、熊猫自定义函数apply()
)
我希望你能发现这些信息,并能把你学到的东西应用到你自己的工作中。感谢阅读!
关于特征工程的更多信息:
特征工程示例:宁滨数字特征
如何使用 NumPy 或 Pandas 快速绑定数字特征
特征工程专注于使用数据集中已经存在的变量来创建额外的特征,这些特征能够(希望)更好地表示数据的底层结构。
例如,你的模型性能可能受益于宁滨数字特征。这实质上意味着将连续或其他数字特征分成不同的组。通过应用领域知识,您可以设计类别和功能,更好地强调数据中的重要趋势。
在本帖中,我们将通过使用 NumPy 和 Pandas 的具体示例,介绍宁滨数字特征的三种不同方法。我们将从一个数据集中设计特征,其中包含关于选民人口统计和参与的信息。我选择了两个数值变量:
- 选举年结束时登记选民的年龄
birth_year
:登记选民出生的年份
如果您想开始将这些方法应用到您自己的项目中,您只需要确保您已经安装了 NumPy 和 Pandas,然后导入它们。
使用 np.where()表示阈值
想想可能有点奇怪,但是指示每个实例(在本例中是每个注册投票者)是否达到某个阈值是一种宁滨。
例如,假设我们试图预测每个注册选民是否在选举中投票。也许我们怀疑,如果这是年轻选民第一次有资格在总统选举中投票,他们更有可能参加投票。由于法定投票年龄为 18 岁,任何在本届总统选举期间不满 22 岁的人都不能在上届总统选举中投票。
我们可以使用np.where()
为这个阈值创建一个指示变量,它有 3 个参数:
- 一种状况
- 如果满足条件,返回什么
- 如果不满足条件,返回什么
以下代码根据个人的年龄创建了一个新特性first_pres_elec
:
df['first_pres_elec'] = np.where(df['age']<22, 1, 0)
我们检查的条件是个人是否小于 22 岁。如果他们低于这个阈值,np.where()
返回 1,因为这是他们有资格投票的第一次总统选举。如果不是,则返回 0。从我们的连续变量age
中,我们创建了一个新的二元分类变量。
也许我们也有理由怀疑老年人或多或少会去投票。如果是这样的话,我们可能希望通过创建另一个阈值指示器来将我们的模型的注意力吸引到这个阈值上:
df['senior'] = np.where(df['age']>=65, 1, 0)
现在我们已经创建了两个阈值指标来划分选民年龄的分布,如下所示。新近有资格在总统选举中投票的年轻人用红色突出显示,老年人用黄色突出显示。
突出显示年轻和年长阈值的登记选民年龄分布-图片由作者提供
使用 apply()应用自定义函数
根据出生年份将我们的注册选民分成几代可能是有意义的,因为这似乎常常与一个人的政治密切相关。一种方法是编写我们自己的自定义函数来描述每一代的临界值。
下面是我们编写这样一个自定义函数的一种方法:
然后使用 Pandas
apply()创建一个基于原始
birth_year`变量的新特性:
现在,我们的注册选民被分成 5 个独立而有意义的类别。我决定将最老的两代人(最伟大的一代和沉默的一代)结合起来,这样就不会产生两个罕见的类别,每个类别只占人口的很小一部分。
Seaborn countplot 按代显示选民分布-按作者显示图像
使用 pd.cut()定义箱
我们也可以使用pd.cut()
来创建相同的生成库,而不是编写我们自己的函数并应用它。我们仍然需要为每个组定义适当的标签,以及 bin 边缘(截止出生年份)。
在最后一行中,我们通过向pd.cut()
提供我们想要分类的列、我们想要的分类以及如何标记每个分类来创建我们的新特性。
我们可以快速创建一个范围,并将其作为我们的 bin 边缘,而不是按代分组。例如,如果我们认为按十年对年龄进行分组是有意义的,我们可以通过以下方法来实现:
第一行定义了一个范围,从 10 开始,一直到 110,但不包括 110,每步增加 10。第二行使用该范围作为绑定边缘,按年龄将注册选民离散化为以下组:
几十年来根据年龄划分的原始计数和注册选民百分比——图片由作者提供
第一行显示 33,349 或 19.84%的选民年龄在 40 岁左右。括号表示 40 岁包括在内,而方括号表示 50 岁不包括在内。为了更容易地跟踪每个 bin 的含义,我们可以向pd.cut()
输入以下标签:
Seaborn countplot 显示了几十年来按年龄划分的选民分布情况-图片由作者提供
概括一下
我们涵盖了:
- 对数字特征进行分类意味着什么
- 1 创建阈值指示器的方法(
np.where()
) - 将宁滨数字特征分组的 2 种方法(用熊猫
apply()
自定义函数,用pd.cut()
定义 bin 边缘)
我希望你能发现这些信息,并能把你学到的东西应用到你自己的工作中。感谢阅读!
关于特征工程的更多信息:
Python 中的要素工程
超越基础
安托万·道特里在 Unsplash 上拍摄的照片
在我十多年作为数据科学家的经历中,我的经验很大程度上同意吴恩达的说法,“应用机器学习基本上是特征工程。”从我职业生涯的一开始,在 SAS 建立信用卡欺诈模型,我作为数据科学家的大部分价值来自于我设计新功能和捕捉数据中观察到的业务见解和行为以帮助模型识别目标的能力。Pedro Domingos 博士的声明也与这种观点一致,“在一天结束时,一些机器学习项目成功,一些失败。有什么区别?最重要的因素无疑是所使用的功能。”
通用特征工程内容
尽管有这些经验和该领域领导者的声明,特征工程内容仍然缺乏。虽然在谷歌上搜索“功能工程”会返回许多页面,但基本内容非常相似,并且只关注几个主题:
- 处理缺失值
- 处理异常值
- 宁滨数值变量
- 编码分类特征
- 数字变换
- 缩放数字特征
- 提取部分日期
这个内容的问题是
这些都是重要的主题,并且在许多情况下,对于底层的机器学习算法甚至能够处理数据都是必要的。然而,它们在三个主要方面有所欠缺。首先,在某些情况下,他们盲目地应用这些技术,却不知道为什么。许多博客讨论了如何在建模前缩放数字要素。这不是真的。基于树的方法,例如 XGBoost、LightGBM 等。对缩放不变。 Praveen Thenraj 在他关于数据科学的帖子中给出了一个很好的例子。
第二,虽然需要这种技术,但在很多问题中,这种技术并不实用,因此需要其他技术。这方面的一个例子是对分类特征进行编码。大多数关于特征工程的讨论都解释了一次性或虚拟编码,并且经常解释标签编码。他们很少讨论高基数分类变量的挑战。我经常在处理邮政编码时看到这种情况,但在处理医疗数据和 ICD-9 或 ICD-10 诊断代码时也会出现这种情况。一键式编码邮政编码可能会产生 40,000 多种新功能。这不是一个实用的解决方案。理解这些代码的结构可以使它们达到更高的聚合级别。即使在聚合之后,对于一键编码或标签编码来说,可能有太多的类别是有用的。此外,一些分类变量没有可减少所需类别数量的易于识别的集合。目标编码或留一编码可以处理这些高基数分类特征。虽然一些特性工程博客讨论了这些技术,但是他们经常没有强调它们在这种情况下的有用性或者一次性编码的不可行性。
特征工程不止于此。
最后,也是最关键的,特性工程远不止这些。当人们谈论特性工程的力量或特性工程的艺术时,他们并不是指这些标准技术。相反,这项工作认识到邮政编码可以聚合到城市、州、DMA 等。并执行这些聚合。通过将这些汇总与该地点的所有采购相结合,可以进一步执行这一工程,以更好地了解当地市场。最后,个人购买和当地整体市场的比较。这只是冰山一角,是数据科学过程中我最喜欢的部分。
公平地说,如果不讨论实际的建模问题,很难展示这种特征工程的例子。但是在讨论特征工程时完全忽略它可能会对它的范围留下一个错误的印象。此外,还有许多强大的技术可以应用于一系列广泛的问题。
时间序列数据的特征工程
例如,许多数据科学问题具有时间序列特征。这并不是说这些问题是时间序列问题,而是有重复的观察结果需要汇总在一起,以表示感兴趣的潜在行为。在构建客户分析模型时(如客户流失、终身价值),单个交易及其随时间变化的方式非常重要。一个特征工程博客可以分享代码,展示如何为此计算公共特征,如下所示。
当处理单个客户在一段时间内的多项观察数据时,聚合这些数据的最常用技术之一是通过滚动窗口,然后在 pandas 中进行聚合。在这种情况下,将创建一个每周聚合,并创建最小、平均、最大和标准偏差。
weekly_resample = df.rolling('7D')
aggregated_df = weekly_resample.agg(['min', 'mean', 'max', 'std'])
aggregated_df.columns = ['_'.join(col).strip() + '_week' **for** col **in**
aggregated_df.columns.values]
注意,要实现这一点,dataframe df
需要日期集作为它的索引。
df.set_index('date', inplace=**True**)
使用滚动窗口,aggregated_df
包含每笔交易的记录,其中汇总了前七天的所有交易。相反,如果每周之后都需要进行预测,则需要额外的工作来过滤出该周之前的最后一条记录。熊猫用resample
支持这个用例。如果改为运行以下代码,则每周返回一条记录。
weekly_resample = df.resample('7D',
origin=pd.to_datetime('2021-01-03'))
aggregated_df = weekly_resample.agg(['min', 'mean', 'max', 'std'])
aggregated_df.columns = ['_'.join(col).strip() + '_week' **for** col **in** aggregated_df.columns.values]
由于 2021 年 1 月 3 日是星期天,所以聚合从每个星期天开始,并包括一周中其余时间的所有交易。如果星期日之前的七天是所期望的,那么可以进行下面的改变。
weekly_resample = df.resample('7D',
origin=pd.to_datetime('2021-01-03'),
lavel='right')
一旦创建了这些每周聚合(任一类型),这些聚合的变化率可能会非常强大。从物理学的角度来看,这是基础特征的速度,我们可以查看多个时间段的变化率。
aggregated_df['velocity_1wk'] = (aggregated_df['mean_week'] -
aggregated_df['mean_week'].shift(1))/7 aggregated_df['velocity_4wk'] = (aggregated_df['mean_week'] -
aggregated_df['mean_week'].shift(4))/28
这给出了一周和四周的周均值变化率。接下来,可以计算这个变化率(加速度)的变化率。
aggregated_df['acceleration_1wk'] = (aggregated_df['velocity_1wk'] -
aggregated_df['velocity_1wk'].shift(1))/7
50 多个免费功能工程教程
像这样的技术可以用来构建能够表示感兴趣的潜在行为的特征。在 Rasgo ,我们希望通过分享这些技术来帮助数据科学界。为了做到这一点,我们创建了一个免费库,专门用于功能工程教程,其中包含功能工程代码,包括上面的例子,作为 Jupyter 笔记本。除了功能工程,还有以下示例:
- 特征分析和 EDA
- 数据清理
- 列车测试分离
- 特征重要性
- 特征选择
用于数据科学、机器学习的日期时间变量的特征工程
了解如何从日期时间类型变量中获取更有意义的特征,以供机器学习模型使用
日期时间变量的特征工程。图片作者。
介绍
日期时间字段需要功能工程来将它们从数据转换为可以被我们的机器学习模型使用的有见地的信息。这篇文章分为三个部分和一个额外的部分。在最后,我们将结合使用内置的熊猫和 NumPy 函数以及我们的函数来提取有用的特性。
- 第 1 部分—提取日期/时间部分
- 第 2 部分—创建布尔标志
- 第 3 部分—计算日期/时间差异
- 奖励——使用
fast_ml
在 2 行代码中实现工程功能
背景
每当我处理与电子商务相关的数据时,以某种方式或其他数据集包含日期时间列。
- 用户注册日期-时间
- 用户登录日期-时间
- 交易日期时间
- 有争议的交易日期时间
- …以及更多
一开始,这个日期字段给我们的只是时间线上的一个特定点。但是这些日期时间字段是潜在的数据宝库。如果使用得当,这些领域对于揭示模式是非常强大的。
作为一名数据科学家,你的工作是将洞察力带到桌面上,为此,你需要提出正确的问题。为了前任。
- 问题 1 —你认为大多数购物车是在什么时候创建的?
- 问题 2 —你什么时候看到大多数手推车被遗弃?
- 问题 3 —您认为什么时候的欺诈交易最多?
- 问题 4 —什么时候订阅的用户最多?
- 某些商品在什么时候最常被购买?
- 问题 6 —注册用户发出第一个订单后多少天/小时?
- 问题 7 —多少天不活动后,客户再也不会回到您的网站?
- …等等
现在,要回答这些问题,您需要回到数据上来设计这些日期时间字段。然后可以发现大量的模式。
帖子的第 1 部分将为您提供特征工程步骤,以回答类似 1、2 & 3 的问题
- Ans 1 —您认为大多数购物车是在什么时候创建的? 本月第一周
- Ans 2 —你什么时候看到大多数手推车被丢弃? 周三下午
- Ans 3 —你什么时候看到的欺诈交易最多? 周五晚
本帖的第 2 部分将为你提供特征工程步骤来回答类似于第 4 部分的问题
- Ans 4 —什么时候订阅用户最多? 年初
- Ans 5——什么时候最常购买某些物品? 月初
帖子的第 3 部分将为您提供特征工程步骤,以回答类似于 6 & 7 中的问题
- Ans 6 —注册用户发出第一个订单后多少天/小时?2 小时内
- Ans 7 —多少天不活动后,客户再也不会回到您的网站?14 天不活动后
我使用了一个电子商务数据的例子,在这个例子中,我个人发现了许多用例,但是提取信息的范围决不仅仅与此相关。在这篇文章中,我们将会看到如何通过问正确的问题来学习一些行为。事实证明,在多个行业中,进行正确的特征工程对于解决各种问题是有用的。
我们开始吧
加载数据集
import pandas as pddf = pd.read_csv('/kaggle/input/loan-data/loan.csv',
parse_dates = ['date_issued', 'date_last_payment'])
Pandas 提供了一种非常简单但非常强大的方法来处理与日期时间相关的变量,将它们解析为日期。您可以将参数parse_dates
中与日期时间相关的所有变量作为列表进行传递。
假设您事先不知道日期时间变量,在调查数据后,您发现一些变量是日期时间。因此,pandas 没有重新加载数据,而是提供了另一个有用的函数to_datetime
来将数据类型转换为 DateTime。
df['date_issued'] = pd.to_datetime(df['date_issued'],
errors = 'coerce')
第一部分。提取日期/时间部分
如上例所示,我们可以从给定的日期-时间变量中提取日期-时间部分的组成部分(year
、quarter
、month
、day
、day_of_week
、day_of_year
、week_of_year
、time
、hour
、minute
、second
、day_part
)。下面的列表提供了几个可以使用 pandas 内置函数提取的组件。
语法:
我们可以使用.dt
访问器提取所有这些组件。在这里阅读更多关于日期访问器的信息
从日期时间变量 issued_date 中提取组件。作者图片
下面是如图所示的代码。所有其他成分也可以用类似的方法提取
#1
df[‘date_issued:year’] = df[‘date_issued’].dt.year#2
df[‘date_issued:month’] = df[‘date_issued’].dt.month#3
df[‘date_issued:day_of_week’] = df[‘date_issued’].dt.day_of_week#4
df[‘date_issued:week_of_year’] = df[‘date_issued’].dt.week_of_year#5
df[‘date_issued:hour’] = df[‘date_issued’].dt.hour
注:
- 周一:
day_of_week = 0
, - 周二:
day_of_week=1
, - …
- 周日:
day_of_week=6
创建日部分:
#day_part function
def day_part(hour):
if hour in [4,5]:
return "dawn"
elif hour in [6,7]:
return "early morning"
elif hour in [8,9,10]:
return "late morning"
elif hour in [11,12,13]:
return "noon"
elif hour in [14,15,16]:
return "afternoon"
elif hour in [17, 18,19]:
return "evening"
elif hour in [20, 21, 22]:
return "night"
elif hour in [23,24,1,2,3]:
return "midnight"
#Run function with apply method
df['date_issued:day_part'] = df['date_issued:hour'].apply(day_part)df.head()
为日期时间变量 issued_date 创建日部分。作者图片
第二部分。创建布尔标志
如上例所示,我们可以从给定的日期-时间变量中提取许多布尔标志(is_month_start
、is_month_end
、is_quarter_start
、is_quarter_end
、is_year_start
、is_year_end
、is_weekend
)。下面的列表提供了几个这样的组件,可以使用 pandas 内置的函数以及通过创建我们的一些函数来提取。
语法:
同样,我们可以使用.dt
访问器来提取许多布尔标志。
从日期时间变量 issued_date 中提取布尔标志。作者图片
#1
df['date_issued:is_year_start'] = df['date_issued'].dt.is_year_start#2
df['date_issued:is_quarter_start'] = df['date_issued'].dt.is_quarter_start#3
df['date_issued:is_month_start'] = df['date_issued'].dt.is_month_start#4
df['date_issued:is_month_end'] = df['date_issued'].dt.is_month_end
创建周末标志:
为日期时间变量 issued_date 创建周末标志。作者图片
如果我们查看日历,我们会发现 2013 年 10 月 26 日是星期六——周末。
df['date_issued:is_weekend'] = np.where(df['date_issued:day_of_week'].isin([5,6]), 1,0)
第三部分。计算日期/时间差异
通常你的问题/分析会与另一个参考点相关。比如,
- 注册后多少天/小时后,用户发出第一个订单?注册 _ 日期&首 _ 订单 _ 日期
- 客户投诉在多少天/小时内得到解决?投诉 _ 日期&解决 _ 日期
- 从今天开始,客户从您的网站订购了多久?今天&最后 _ 订单 _ 日期
- …等等
在我们的示例数据集中,我们有两列 date_last_payment & date_issued。让我们看看当我们取这两列的差时会发生什么。
计算熊猫的时差。图片作者。
默认情况下,熊猫提供“天”的差异。注意dtype: timedelta64[ns]
。
来自 numpy 文档:
因为 NumPy 的核心没有物理量系统,所以创建了 timedelta64 数据类型来补充 datetime64
现在,如果我们只想要数字部分而不是整个字符串947 days
,我们可以通过使用。dt 访问器。
计算熊猫的时差。dt 访问器。图片作者。
不幸的是,我们不能以类似的方式得到月份。
计算熊猫的时差。dt 访问器不可伸缩。图片作者。
这里 NumPy 的timedelta64
变得非常有用。
语法:
为了得到贷款发放日期和最后一次付款日期之间的月数,我们将这样写
使用 NumPy timedelta64 计算熊猫的时差。图片作者。
(df['date_last_payment'] - df['date_issued'])/np.timedelta64(1, 'M')
timedelta64 可以采用以下参数来计算两个日期之间的差异:
- d’→持续几天
- w’→数周
- ' M' →几个月
- 多年来
- h’→数小时
奖金!
您可以使用 fast_ml 来创建所有这些日期时间特性
首先,安装fast_ml
包
!pip install fast_ml — upgrade
然后,从feature_engineering
模块导入工程日期时间特征的方法
from fast_ml.feature_engineering import FeatureEngineering_DateTime
现在,这与 sklearn 的其他变形金刚、预处理器的工作方式完全相同。
- 例示
- 合适的
- 改变
#Instantiate
dt_fe = FeatureEngineering_DateTime()#Fit
dt_fe.fit(df, datetime_variables=['date_issued'],
prefix = 'date_issued:')#Transform
df = dt_fe.transform(df)
df.head()
使用 Fast_ml 对日期时间变量进行特征工程。图片作者。
在屏幕截图中,所有的列都不可见。让我们只看数据集的列
df.columns---Output---
Index(['customer_id', 'disbursed_amount', 'interest', 'market', 'employment', 'time_employed', 'householder', 'income', 'date_issued', 'target', 'loan_purpose', 'number_open_accounts', 'date_last_payment', 'number_credit_lines_12',(Notice from here ------->)
'date_issued:year', 'date_issued:quarter', 'date_issued:month', 'date_issued:day', 'date_issued:day_of_week', 'date_issued:day_of_year', 'date_issued:weekofyear', 'date_issued:is_month_end', 'date_issued:is_month_start', 'date_issued:is_quarter_end', 'date_issued:is_quarter_start', 'date_issued:is_year_end', 'date_issued:is_year_start', 'date_issued:time', 'date_issued:hour', 'date_issued:minute', 'date_issued:second', 'date_issued:is_weekend', 'date_issued:day_part'],
dtype='object')
感谢阅读!!
- 如果你喜欢这个,在 medium 上跟随我了解更多。
- 有兴趣合作吗?让我们在 Linkedin 上连线。
- 请随意写下您的想法/建议/反馈。
- 卡格尔链接
- Fast_ml 链接
笔记本可在以下位置获得,并附有完整的功能代码:
用于人体活动识别的时间序列数据特征工程
转换智能手机加速度计的原始信号数据,并从中创建新的功能来识别六种常见的人类活动。
目标
在出于研究兴趣探索人类活动识别领域时,我看到了一些出版物、研究文章和博客。研究人员在这一领域做了非凡的工作,并通过使用一些复杂的机器学习算法实现了最先进的(SOTA)结果。但是我读过的大多数论文/博客要么使用已经设计好的特征,要么没有详细解释如何从原始时间序列数据中提取特征。
在本文中,我们将探索不同的技术来转换原始时间序列数据,并从中提取新的特征。
我们将在本文中看到的技术不限于人类活动预测任务,而是可以扩展到任何涉及时间序列数据的领域。
关于数据
Smarphones 和智能手表包含三轴加速度计,可测量所有三个空间维度的加速度。这些加速度计能够检测设备的方向,这可以为活动识别提供有用的信息。
我们将在本次演示中使用的数据集来自纽约州布朗克斯福特汉姆大学计算机与信息科学系 WISDM 实验室(链接到数据集)。请注意,我们将使用的文件是原始数据文件— WISDM_ar_v1.1_raw.txt
这些数据是从 36 名不同的用户那里收集的,他们进行了一些常见的人类活动,如行走、慢跑、爬楼梯、下楼梯、坐着和站一段时间。在所有情况下,每 50 毫秒收集一次数据,即每秒 20 个样本。
共有 5 个特征变量——“用户”、“时间戳”、“x 轴”、“y 轴”和“z 轴”。目标变量是我们打算预测的“活动”。
“用户”表示用户 ID,“时间戳”是以纳秒为单位的 unix 时间戳,其余是在给定时间沿 x、y 和 z 轴/维度的加速度计读数。
这是原始数据集的一瞥—
如您所见,有超过 100 万行和 6 列。此外,数据需要清理和组织。
数据清理和预处理
我们根据观察结果执行以下步骤—
- 删除空值。
- 将“z 轴”列的数据类型更改为浮点型。
- 删除时间戳为 0 的行。
- 按照用户和时间戳的升序对数据进行排序。
这是我们的数据经过清理和分类后的样子—
如你所见,我们剩下 1085360 行。
探索性数据分析
分析类别标签分布—
sns.set_style(“whitegrid”)
plt.figure(figsize = (10, 5))
sns.countplot(x = ‘activity’, data = df)
plt.title(‘Number of samples by activity’)
plt.show()
正如你所看到的,这里有一个明显的类别不平衡,大多数样本的类别标签为“散步”和“慢跑”。站立和“坐着”活动在数据集中最少出现。
现在让我们看看用户是如何对每项活动做出贡献的。这将有助于我们决定如何分割数据用于训练和测试。
plt.figure(figsize = (18, 6))
sns.countplot(x = ‘user’, hue = ‘activity’, data = df)
plt.title(‘Activities by Users’)
plt.show()
可以看出,不是所有的用户都在执行所有的活动。他们进行每项活动的时间也各不相同。无论如何,这不会影响我们后续的分析,因为我们有足够多的数据样本,并且我们假设所有的用户都是一样的。
对于一个特定的用户,让我们观察在每个 x,y 和 z 维度上的信号值如何随时间变化。
for i in [‘Walking’, ‘Jogging’, ‘Upstairs’, ‘Downstairs’, ‘Sitting’, ‘Standing’]:
data_36 = df[(df[‘user’] == 36) & (df[‘activity’] == i)][:400]
plt.figure(figsize = (15, 6))
sns.lineplot(y = ‘x-axis’, x = ‘timestamp’, data = data_36)
sns.lineplot(y = ‘y-axis’, x = ‘timestamp’, data = data_36)
sns.lineplot(y = ‘z-axis’, x = ‘timestamp’, data = data_36)
plt.legend([‘x-axis’, ‘y-axis’, ‘z-axis’])
plt.ylabel(i)
plt.title(i, fontsize = 15)
plt.show()
我们考虑了 400 个样本的子集来可视化信号。这相当于 20 秒的活动(因为数据收集的频率是 20 Hz)。正如你所注意到的,信号显示了行走、慢跑、上楼和下楼等活动的周期性行为,而坐着和站着等静止活动的运动很少。
现在,让我们观察信号数据沿 x、y 和 z 轴的活动分布,看看是否有任何基于值的范围和分布的明显模式。
sns.FacetGrid(df, hue = ‘activity’, size = 6).map(sns.distplot, ‘x-axis’).add_legend()
sns.FacetGrid(df, hue = ‘activity’, size = 6).map(sns.distplot, ‘y-axis’).add_legend()
sns.FacetGrid(df, hue = ‘activity’, size = 6).map(sns.distplot, ‘z-axis’).add_legend()
据观察,在像上楼、下楼、散步、慢跑和站在所有轴上这样的活动中,数据有非常高的重叠。坐着似乎在 y 轴和 z 轴上有独特的值。
这就把我们带到了文章的核心,那就是数据转换和特征工程。
数据转换
标准分类算法不能直接应用于原始时间序列数据。相反,我们必须首先使用“窗口”技术转换原始时间序列数据。在这种技术中,我们将数据划分为 5 秒的窗口,然后通过聚合这 5 秒时间段内包含的 100 个原始样本来生成新特征。为了根据变换后的特征分配类别标签,我们采用该窗口中最频繁的活动。
例如,假设一个原始数据集有 100 行顺序数据。所以在开窗和聚合(使用窗口大小= 50)之后,它将被转换为 2 行。为这 2 个新行分配的类别标签将是相应窗口中最频繁的活动。同样,对于 100 万行,我们将在转换后的集合中获得将近总共 20k 行。
您一定想知道为什么选择 5 秒的窗口。在查阅了一些文献后,我觉得这可能是我们可以考虑的最佳窗口大小,用于捕捉六种活动中大多数活动所涉及的重复运动。太小的窗口尺寸可能不能正确地捕捉运动,而太大的窗口尺寸导致用于训练的变换数据集中的数据点更少。
这里我们还可以做一件事——我们采用 50%重叠的重叠窗口,而不是离散窗口。这确保了转换后的数据集中的每个后续行也具有来自前一个窗口中的数据的一些信息。
所有这些特征一开始可能听起来有点令人生畏,但是相信我,它并没有那么复杂。慢慢地再读一遍这一部分,因为如果你很好地理解了这一点,后面的部分将会很容易。我在这里附上这张图片,它将帮助您清楚地了解原始信号数据是如何聚合并转换为新功能的。
左:原始数据集右:转换数据集|作者的图像
特征工程
在我们开始设计新功能之前,我们必须首先将数据分为训练和测试。通常我们倾向于进行随机拆分,但是在这个特定的场景中,按照用户 ID 进行拆分更有意义。
因此,在总共 36 个用户中,前 27 个用户的数据将形成我们的训练数据,而其余 9 个用户将包括在我们的测试数据中。
# train data -> Users upto User ID = 27 (i.e. 27 users)
df_train = df[df[‘user’] <= 27]# test data -> Users from User ID = 28 to 36 (i.e. 9 users)
df_test = df[df[‘user’] > 27]
通过这样做,我们在训练集中获得了大约 804358 个数据样本,在测试集中获得了 281002 个样本。这就像做 75-25 分割,但方式更复杂。
特征工程阶段 1:统计测量
在特征工程的第 1 阶段,我们将构建总共 18 个简单的统计特征—
1。意思是
2。标准差
3。平均绝对偏差
4。最小值
5。最大值
6。最大值和最小值之差
7。中位数
8。中位数绝对偏差
9。四分位距
10。负值计数
11。正值计数
12。以上数值的数量表示
13。峰值数量
14。偏斜度
15。峰度
16。能源
17。平均合成加速度
18。信号幅度区域
这些特性中的大多数都是不言自明的。
- 每个轴上信号的能量 通过取该特定轴上窗口中值的平方和的平均值来计算。
- 窗口上的平均合成加速度通过取三个轴的平方值的平方根的平均值并相加计算得出。
- 信号幅度面积定义为一个窗口内三个轴的绝对值之和。
下面的 python 代码将更加清晰地给出上述每个特性的数学公式。
x_list、y_list 和 z_list 中的每一个实际上都是窗口的列表。每个窗口由 100 个观察值组成。因此总共应该有 int(804358/50) -1 = 16086 个窗口(您可以从代码中验证这一点)。 X_train 是我们根据转换后的特征构建的新特征数据框架。从今以后,我们将使用这个新的数据框架,并逐步增加新的特征,最终用它来训练 ML 模型。
特征工程阶段 2:快速傅立叶变换(FFT)
傅立叶变换是将时域信号变换到频域的函数。该函数接受时间信号作为输入,并产生信号的频率表示作为输出。现实世界中的每个信号都是时间信号,由许多不同频率的正弦波组成。
傅立叶变换不会改变信号。它只是提供了一个不同的角度来分析您的时间信号,因为信号的一些属性和特征可以在频域中充分探索。
到目前为止,我们一直在处理时间域。让我们从数据中选取任意一个随机窗口,观察它的离散傅立叶变换——
pd.Series(np.fft.fft(pd.Series(x_list)[42])).plot()
plt.show()
一些观察—
- 第一个值异常高。在电气术语中,这被称为“DC 分量”或“DC 偏移”。
- 波信号关于中心对称。
这些观察结果并不是这个特定窗口所特有的,但是如果你从我们的时域数据中选取任何一个窗口,并在其上应用 FFT,你会得到相同的观察结果。
不要太在意 DC 分量,把它想成一个我们将要丢弃的异常高的值。我们也将只考虑信号的前半部分。这将确保我们从中获得无偏的统计特征。
就像第一阶段一样,在第二阶段,我们将通过聚集傅立叶变换的数据来构建新的特征
到特征工程的前两个阶段结束时,我们现在总共有 94 个特征!这就把我们带到了特征工程的第三阶段。
特征工程阶段 3:捕获索引
在任何机器学习问题中,特征工程阶段的主要目标是为模型提供尽可能多的信息。你提供的信息越多,它学得越好!
那么在这种情况下,为什么不把底层数据的索引值作为潜在的特征呢?
同样,按照上述步骤转换原始测试数据帧 df_test 和从中提取特征,以构建转换后的测试数据集,即 X_test 。为了简洁起见,我在文章中跳过了这一部分。新的 X_test 数据集将具有 int(281002/50)-1 = 5619 行(您可以在自己的终端验证这一点)。
这就把我们带到了本文的最后一节。既然我们已经生成了如此多的特征,是时候看看这些新手工制作的特征能在多大程度上预测人类活动了。
实现用于活动预测的线性模型
对于预测任务,我们将在转换后的训练数据上训练简单的逻辑回归模型,然后评估转换后的测试数据的性能。其思想是,逻辑回归是一个线性分类器,它严重依赖于特征的质量,以便给出好的结果。功能提供的独特信息越多,性能就越好。因此,如果我们能够使用逻辑回归获得更好的性能,那么我们可以说我们已经成功地创建了正确的特征集。
逻辑回归模型
y_train = np.array(train_labels)
y_test = np.array(test_labels)
对于 logistic 回归,建议先将数据标准化。
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report# standardization
scaler = StandardScaler()
scaler.fit(X_train)
X_train_data_lr = scaler.transform(X_train)
X_test_data_lr = scaler.transform(X_test)# logistic regression model
lr = LogisticRegression(random_state = 21)
lr.fit(X_train_data_lr, y_train)
y_pred = lr.predict(X_test_data_lr)
print("Accuracy:", accuracy_score(y_test, y_pred))
print("\n -------------Classification Report-------------\n")
print(classification_report(y_test, y_pred))
输出—
通过对工程特征使用基线逻辑回归模型,我们成功地获得了 84.53 %的测试数据的总体准确度。考虑到我们在开始时只有原始加速度计数据的 3 个特征,这是相当不错的。通过使用一些复杂的分类模型,如基于树的集成、投票或堆叠分类器,在准确性和其他性能指标方面还有改进的余地。
从分类报告中可以看出,大多数活动的总体表现相当不错。尽管在识别这两种爬楼梯活动时有些困难。这是意料之中的,因为这两个活动非常相似。让我们检查一下混淆矩阵。
labels = [‘Downstairs’, ‘Jogging’, ‘Sitting’, ‘Standing’, ‘Upstairs’, ‘Walking’]
confusion_matrix = confusion_matrix(y_test, y_pred)
sns.heatmap(confusion_matrix, xticklabels=labels, yticklabels=labels, annot=True,linewidths = 0.1, fmt=”d”, cmap = ‘YlGnBu’)
plt.title(“Confusion matrix”, fontsize = 15)
plt.ylabel(‘True label’)
plt.xlabel(‘Predicted label’)
plt.show()
从分类报告和混淆矩阵可以看出,我们的数据集中最常见的两个类别慢跑和步行被正确识别,具有良好的准确性。虽然很少有坐和站类的样本,但我们仍然可以很好地识别这些活动,因为这两种活动会导致设备改变方向,这很容易从加速度计数据中检测到。为了更准确地区分楼上的和楼下的活动,现有的一组特征是不够的。通过将三轴加速度计数据与三轴陀螺仪(智能设备中的另一种惯性传感器)的数据相结合,可以区分这些类别,并以更高的精度识别其他活动。**
结束注释
我们从 3 个特征开始——三轴加速度计信号在 x 、 y 和 z 轴上的读数。我们从原始数据中逐步设计特征,最终,我们成功提取了总共 112 个独特的特征!后来我们训练了一个简单的线性分类器并评估了它的性能。
正如你可能已经意识到的,为了形成这些新的特征,我们依赖于统计学和数学的基本概念。没有使用高端信号处理或先进技术。此外,我们在本文中使用的数据准备和特征工程技术是通用的,可以应用于大多数涉及时间序列数据的问题。
参考
- 詹妮弗·r·夸皮什、加里·m·韦斯和塞缪尔·a·摩尔(2010 年)。使用手机加速度计的活动识别,第四届传感器数据知识发现国际研讨会会议录(KDD-10),华盛顿州 DC。
- 达维德·安吉塔、亚历山德罗·基奥、卢卡·奥内托、哈维尔·帕拉和豪尔赫·雷耶斯-奥尔蒂斯。使用智能手机进行人类活动识别的公共领域数据集。第 21 届欧洲人工神经网络、计算智能和机器学习研讨会,ESANN 2013。
【免责声明:本文使用的所有图片均为作者所有,除非明确提及】
特征工程序数变量
深度指南
揭示序数特征编码中的微妙之处,以避免潜在的缺陷并提高效率
杰西·多兹在 Unsplash 上的照片
我正在和一个业务/数据分析相对较新的团队一起工作,这时关于机器学习的特征工程的小组讨论开始了。可以理解的是,对于机器学习的新手来说,这可能会令人困惑和害怕。在 Jupyter 笔记本和 Python 中工作,我们自然会参考 Pandas 和 Sklearn 等包中的内置文档,或者 2)这些包的在线、深入的技术文档。有趣的是,该文档没有详细说明解决团队面临的数据集特定问题的方法——多个序数变量的特征工程,每个变量都有唯一的排序序列。
分类变量介绍
🔆 代码实现 安排在本节之后。
❓什么是分类变量?
📔分类变量按具有相应值范围的组排列(即组标签)。没有固有层次的变量为名义变量;组标签是任意的。具有有序序列的变量是序数变量;组标签按升序/降序排列。
❓:这和特征工程有什么关系?
📔对于许多算法(机器学习模型),输入必须是数字。因此,分类变量需要转换成数值。下面的代码实现说明了一些避免潜在缺陷的特性工程技术和步骤。
代码实现
# Begin by importing the librariesimport pandas as pd
import numpy as np
from sklearn.preprocessing import OrdinalEncoder
from sklearn.preprocessing import LabelEncoder# Create a dataframe with artifical values
# Salary Grade, G to L, G ranked highest
# Sector Ranking, SR1 to SR9, SR1 ranked highest
# retentionRisks, Low, Med, High
Grades = ['K', 'I', 'G', 'L', 'H', 'G', 'H', 'I', 'K'] # mixed to see effect
SRs = ['SR1', 'SR9', 'SR2', 'SR8', 'SR3', 'SR7', 'SR4', 'SR6', 'SR5'] # mixed to see effect
retentionRisks = ['Low', 'High', 'Low', 'High', 'Low', 'Med', 'Low', 'High', 'Med']
Ex = pd.DataFrame({'grades':Grades,
'ranks':SRs,
'retnRisks':retentionRisks
})
Ex
数据集|按作者分类的图像
示例数据集包括三列(等级、排名和保留风险——缩写为“ retnRisks ”)。为了说明的目的,所有的都是故意分类的。让我们假设保留风险为目标变量(机器学习分类输出的变量)。
# Split the dataset
X_Ex = Ex.loc[:,:'ranks']
y_Ex = Ex['retnRisks']
📓有些人可能想知道这里的大写和小写的区别。通常,这是一种记录预测变量(X_Ex)和目标变量(y_Ex)之间差异的方法。目标变量是熊猫系列。让我们从目标变量开始。
# Let's look at the target variable first# Instantiate the label encoder
label_encoder = LabelEncoder()# Assign the encoded values to y_ExT
y_ExT = label_encoder.fit_transform(y_Ex)# Code block to review encoding
y_Exunique = np.unique(y_Ex)
y_ExTunique = np.unique(y_ExT)
y_encode = dict(zip(y_Exunique, y_ExTunique))
print(y_encode)
结果编码|作者图片
无论是升序还是降序,编码顺序都不符合要求。对于以上内容,排序顺序是按字母顺序的。理想情况下,我们希望每高(2)>中(1)>低(0)。我们可以通过熊猫做到这一点。
# Define a dictionary for encoding target variable
enc_dict = {'Low':0,
'Med':1,
'High':2}# Create the mapped values in a new column
Ex['target_ordinal'] = Ex['retnRisks'].map(enc_dict)# Review dataset
Ex
结果数据集|按作者分类的图像
接下来,预测变量。
# Instantiate ordinal encoder
ordinal_encoder = OrdinalEncoder()# Assign the encoded values to X_ExT
X_ExT = ordinal_encoder.fit_transform(X_Ex)# define function to return encoded values for categorical variable values
def enc(array, frame):
for idx in range(array.shape[1]):
X_Exunique =sorted(frame.loc[:,frame.columns[idx]].unique())
X_ExTunique = np.unique(array[:,idx])
encode = dict(zip(X_Exunique, X_ExTunique))
print(encode)# Check encoding using the func
enc(X_ExT, X_Ex)
结果编码|作者图片
编码序列是好的,除了在数据集的上下文中,对于等级,‘G’的排名高于‘L’。类似的情况也适用于军衔。我们需要颠倒顺序。我们可以这样做:
# Create lists to hold the order sequence needed# for grades
g = sorted(Ex['grades'].unique(),reverse=True)# for ranks
r = sorted(Ex['ranks'].unique(),reverse=True)
按作者排序 g |图像的顺序
作者对 r |图像的排序顺序
Sklearn 的顺序编码器接受一个参数 categories。
来自 Sklearn 文档
- ‘自动’—意味着按字母顺序排列
- ‘列表’—指的是具有我们想要的序列的两个列表。它们传入编码器的顺序必须与数据集中变量的顺序一致。
# Pass in the correctly-ordered sequence into Ordinal Encoder
ordinal_encoder = OrdinalEncoder(categories=[g,r])
X_ExT2 = ordinal_encoder.fit_transform(X_ex)# grades
X_ExT2_grades_unique = np.unique(X_ExT2[:,0])grades_encode = dict(zip(g, X_ExT2_grades_unique))
grades_encode
结果编码|作者图片
# ranking
X_ExT2_rank_unique = np.unique(X_ExT2[:,1])rank_encode = dict(zip(r, X_ExT2_rank_unique))
print(rank_encode)
结果编码|作者图片
杂项笔记
- 数据输入。数据输入的另一种方法是获取值,然后适当地处理它们。
# Alternative data load approach
Ex_values = Ex.values# Predictor variables
X_ = Ex_values[:, :-1].astype(str)# target variables
y_ = Ex_values[:,-1].astype(str)
- 值的范围。对于编码器,当前的默认设置是,如果有编码器在拟合过程中没有看到的新值,则引发错误。这可以根据文档进行配置。另一种方法是列出要编码的预期值的完整范围,并将它们传递给编码器。
摘要
概括一下,
- 不管目标变量还是独立变量(即预测变量),我们都需要理解正确的顺序,然后相应地应用编码。在对每一列进行编码后检查编码值总是一个好主意。
- 对于目标变量,我们可以选择使用标签编码器或熊猫。
- 对于独立变量,我们可以在 Pandas 上使用顺序编码器,以提高处理效率。
- 在排序序列是唯一的情况下,可以定义排序序列并将其传递给编码器。
特征工程技术
将原始数据映射到机器学习特征
特征工程是开发机器学习模型的关键步骤之一。这涉及从原始数据中选择、聚集或提取特征的任何过程,目的是将原始数据映射到机器学习特征。
将原始数据映射到特征向量。(图片由作者提供)。
应用于数据的特征工程过程的类型取决于其数据类型。数字和非数字数据是原始数据中可以出现的两种基本数据类型;这些可以细分为离散、连续、分类、文本、图像和时间数据类型。
这篇文章的重点是特征工程数字,分类和文本数据。它还考虑了处理缺失数据和派生新特征以提高模型性能的方法。
已经读入 Pandas 数据帧的数据的数字和非数字列可以根据其列的数据类型来区分,因此:
获取数据帧中的数字和非数字列。(图片由作者提供)。
数值数据是保存可以按逻辑顺序排列的数值的特征数据的通称。在机器学习中,以数字数据格式(整数、浮点数等)处理数字特征通常更容易。)可被机器学习算法摄取。
例如,让我们看看流行的房价数据集的一些数字数据。
房价数据集的示例数字列。(图片由作者提供)。
原始数据的数值数据通常以不同的尺度表示。就像上面的例子一样,一些列如“全浴”和“半浴”具有较低的比例(<10) while others such as “1stFlrSF” and “2ndFlrSF” have higher scales ( > 1000)。将输入数值数据的比例标准化为具有相似的范围通常是一种好的做法,以避免算法在训练过程中为比例较大的要素分配更多权重。
数字数据可以使用 Sklearn 的 MinMaxScaler 或 StandardScaler 进行缩放。最小最大值定标器将所有数值数据的范围定标为 0 到 1,而标准定标器将数值数据的单位方差和平均值定标为 0,从而将数值输入标准化。
使用 MinMaxScaler 缩放数值数据。(图片由作者提供)。
非数字数据包括分类和文本数据,这些数据在被摄取到机器学习模型中之前通常被编码成数字。
分类数据有时可以表示为数字,但不要与数字数据混淆,因为它们显示了不同类别数据之间的关系。下面是房价数据集的一些分类列的数据框架。
显示分类特征的房价数据集的示例列。(图片由作者提供)。
为了避免在训练期间假设以数值表示的分类数据是数字特征,通常最好对分类特征进行一次性编码,而不是对它们进行标签编码,这可能会欺骗机器学习算法来假设类别之间的代数关系。
与标签编码中简单地分配数值来表示各自的类别不同,在一键编码中,每个分类值被转换成新的分类列,并被分配二进制值 1 或 0,从而将每个值表示为二进制向量。这防止了算法假设数字排序或类别之间的关系(例如假设一个男孩>一个女孩,如果他们分别用 1 和 0 进行标签编码),从而提高了模型在学习数据内的关系时的性能。
根据前面的例子,下面是来自房价数据集的样本分类列的子部分。
波士顿住房数据集的分类列示例。(图片由作者提供)。
与其像在模型摄取的标签编码中那样用数值(0,1,2,3,…)来表示这些列中的每个类别,不如对数据帧中的特征进行一次性编码,这样,数据点中类别的存在用一(1)来表示,而不存在用零(0)来表示。这可以通过使用 Scikit Learn 的 oneHotEncoder 轻松完成。
分类列的一个热编码特征。(图片由作者提供)。
结果显示,一次性编码的特征可以被吸收到模型中以获得高效的性能。请注意,输出数据帧现在包含更多维度(列),这些维度具有代表每个数据点中是否存在该类别的数值(1.0,0.0)。因此,对于所有分类列,每个列都根据该列中类别的数量展开为单独的列。
对于文本数据,有必要将它们表示为数值,机器学习算法通过称为矢量化的过程识别这些数值。一些常见的文本矢量化技术有字数统计、词频-逆文档频率(TF-IDF)和单词嵌入。
字数统计是一种简单的矢量化技术,它根据文本数据在数据中出现的频率将文本数据表示为数值。例如,考虑下面的文本列表:
text_data = ['Today is a good day for battle',
'Battle of good against evil',
'For the day after today is Monday',
'Monday is a good day for good']
为了使用字数统计技术对上述文本数据进行矢量化,通过记录每个单词在文本数据中出现的次数来形成稀疏矩阵。这可以通过使用 Scikit Learn 的计数矢量器来实现。
示例文本数据的字数矢量化输出数据帧。(图片由作者提供)。
输出数据帧显示了输入文本数据的矢量化特征,这些特征现在可以被摄取到算法中。虽然这种技术实现了向量化的目的,但对于机器学习算法来说,它不是最佳的,因为它只关注数据中单词的频率。一个更好的替代方法是术语频率-逆文档频率(TF–IDF)方法,该方法关注单词的频率及其在文本数据中的重要性。
在 TF-IDF 中,文本数据中每个单词的重要性由该单词的逆文档频率(IDF)来推断。逆文档频率是一种统计度量,用于评估单词与文本集合中的文本的相关程度。每个单词的 IDF 计算如下:
idf = ln[1+N]/(1+df)]+1
where:
idf = Inverse document frequency
N = Number of texts in the data, N=4 for our example.
df = the document frequency
The df is the number of texts that a particular word appears in the data; for instance, the word "good" appears four (4) times in the data but has a df of (3) as it appears in 3 texts (once for two texts and twice for another text).
TF-IDF 方法的一个重要方面是,它为文本数据中丰富或稀少的单词分配较低的分数,因为它假设它们在数据中寻找模式时不太重要。这通常有助于建立有效的模型,因为诸如“the”、“is”、“are”、“of”之类的常用词和罕见词在文本数据中的实时模式识别中大多很少或没有帮助。Sklearn 的 TfidfVectorizer 有助于以这种方式轻松地对文本数据进行矢量化。
显示数据中单词的逆文档频率的输出数据帧。(图片由作者提供)。
输出显示文本数据根据单词的 TF-IDF 值被矢量化,然后可以被摄取到算法中用于学习。TD-IDF 方法的缺点是,它没有考虑在单词嵌入中共享相似含义的单词;尽管如此,它仍然非常适合向量化文本数据。
通过特征工程来提高机器学习模型的性能的另一种常见技术是通过从现有特征中导出新特征。这可以通过以某种方式对输入特征进行数学组合来实现,从而在对输入特征进行训练之前对其进行转换。
例如,在房价数据集中,诸如每间房的平方英尺或房屋中房间总数等特征通常比诸如卧室、浴室等的数量等单个特征更能反映和指示房屋的目标价格。如果数据中不存在此类有用的特征,则可以通过对输入特征进行数学组合来获得这些特征。
在机器学习中处理原始数据时,缺失数据也是另一个问题。处理缺失数据是特征工程的一个重要方面,因为原始数据通常是不完整的。处理数据中的缺失值通常包括完全删除缺失值的数据点,通过利用任何集中趋势(平均值、中值或众数)或矩阵补全来替换缺失值。
在根据数据类型执行了之前概述的大多数步骤之后,您的原始数据现在被转换为特征向量,这些向量可以被传递到机器学习算法中以用于训练阶段。
总结:特征工程涉及将原始数据映射到机器学习特征的过程。特征工程的过程取决于数据的类型。常见的特征工程过程包括缩放数字数据、标签或一次性编码分类数据、矢量化文本数据、导出新特征和处理缺失数据。适当的特征工程有助于使原始数据适合摄取到机器学习模型中,并提高机器学习模型的性能。
基于梯度增强决策树的特征生成
实践教程
拉布雷尼亚,巴尔巴特,加的斯,作者安达卢西亚军政府
TL;速度三角形定位法(dead reckoning)
在这篇博客中,我们实现了之前在脸书人工智能研究论文中提到的一个想法: 在脸书 预测广告点击的实际经验
其思想是使用梯度推进决策树创建特征的非线性变换,然后使用最终估计器进行预测。
该实现是托管在 sktools 包中的 python 管道转换器,可以通过以下方式下载:
pip install sktools
和一些代码片段来集成以再现它
介绍
在机器学习任务的建模过程中,需要创建新的特征来描述问题并使模型达到更好的性能,这就是所谓的“特征工程过程”。这是每个机器学习项目周期的一部分。
在创建这些新功能的整个设计过程中,我们必须了解手头的任务,寻找功能的相互作用,尝试想象这个新功能如何与其他功能一起工作,考虑宁滨连续功能,创建最佳数量的四分点,以有助于提高线性回归性能的方式处理分类功能。所有这些都是在高维空间中,我们对二维或三维空间的直觉已经产生了误导。该过程不仅需要领域知识、耗时且容易出错,而且还依赖于问题,并且必须为每个新数据集开发方法和函数。不要忘记,并不能保证创建功能在任何时候都能达到最佳性能,这取决于人类的创造力和耐心。
在可以应用于任何问题的框架中,自动生成特征允许提取数据中更有用和更有意义的信息。允许机器学习工程师在更有用的任务上花费更多时间。
利用梯度增强决策树生成特征
决策树基于分类和回归树(CART)方法构建二元分裂。在每次树分裂时,基于损失函数的优化来选择分离的最佳选择。在建立了几个分支之后,我们就有了一个树状结构,其中某个单独的预测最终会出现在不同的树叶中。
如果单个预测/一行/实例大于 X_i 中的某个值,则它将向右,否则它将向左。典型的二叉决策树分裂。
决策图表
对于图中的决策,每个实例有五种可能性:[0,0,0,0,1],[0,0,0,1,0],[0,0,1,0,0],[0,1,0,0,0]和[1,0,0,0,0,0]。
给定任何数据集,在训练一个 GBM 之后,每个实例都可以根据它从每棵树中感受到的叶子进行编码。如果 GBM 由 N 个决策树的集合组成,那么每个实例将有 N 种编码。
编码的特征集可以水平地附加到先前的特征上,增加了问题的维度,并且增加了源自每个决策树执行的不同分裂的新的非线性信息。
一些实验
在本节中,我们提供了几个基准来比较算法的性能。
逻辑 —指逻辑回归
梯度推进 —梯度推进决策树
GB 特性 —指的是前面提到的算法,其中特性通过梯度推进决策树进行转换,最终的估计器是逻辑回归。
用一些数据集对算法进行基准测试
上图是我们对算法进行基准测试的七个数据集的条形图。每组条形代表使用三种方法的数据集的结果。每个条形都有一个相关的标准偏差来衡量预测的稳定性。在较小的数据集中,每次分割之间的差异往往较大,而在较大的数据集中,相似性往往较大,这解释了数据集之间标准差大小的差异
代码片段
安装 sktools 软件包
pip install sktools
将特征工程技术集成到具有最终估计器的流水线中
分类
该实现处理几个超参数
*stack_to_X: bool, default = True*
如果设置为 True,则返回原始列加上由梯度提升决策树算法生成的新列。如果为 False,则仅返回新列。
*add_probs: bool, default = False*
如果设置为 True,它将返回创建的要素加上通过梯度增强估计的概率。请注意,这可以被视为一个集合。然而,默认值是 False,所以不会附加任何概率。
scikit-learn 梯度推进的所有论点也可以通过。
回归
为了将其构建为回归问题,需要修改超参数regression = True
。
请注意,这种特征生成技术可以视为一个整体,因此在验证过程中必须特别小心。
感谢
这个项目是之前在巴塞罗纳超级计算中心与大卫·布查卡(T2)一起完成的。
sktools python 包由大卫·马斯普主持。
非常感谢 Vincent Warmerdam 在https://calmcode.io/发布的关于开源的酷视频
线性模型中的特征重要性:四个经常被忽视但却至关重要的陷阱
作者图片
线性模型家族包括普通线性回归、岭回归、套索回归、SGD 回归等等。线性模型的系数通常被解释为相关变量的特征重要性。一般来说,特征重要性指的是特征在预测目标变量时的有用程度。比如 房龄 在预测房价上有多有用。
本文总结并解释了使用线性模型的系数作为特征重要性时经常被忽略但却至关重要的四个陷阱:
- 是否标准化数据集
- 线性模型有不同意见
- 高度相关特征的诅咒
- 交叉验证的稳定性检查
线性回归模型采用以下形式
其中 𝒚 表示预测的目标值, 𝑤 为系数, 𝑥 为变量或特征。
为了简单起见,让我们用一个简单的例子:基于三个特征房屋年龄房间数量平方英尺来预测房屋价格。
数据集如下所示:
假设我们将数据集提供给一个线性模型,然后训练该模型,进行预测,此时,我们有系数值:
现在,我们回到最初的问题:我们的特征的重要性是什么:房子的年龄,房间的数量,平方英尺?它们在预测房价方面有多大用处?是否可以说它们的重要性等于系数:[20,49,150]?
数据集是否标准化
答案是:只有数据集在训练前被标准化,系数才能作为特征重要度。
例如,如果我们将标准缩放器应用于原始数据集,然后将其拟合到模型,我们可以说 age_of_a_house 的特征重要性是 20 。
原因是变量通常处于不同的尺度。 房间数 大多在【1,10】范围内,而 平方英尺 可以在【500,4000】范围内。在这种情况下,变量需要缩放到相同的度量单位。如果数据集是标准化的,系数是线性模型的特征重要性。
线性模型有不同意见
不同的线性模型可能对特征的重要性有完全不同的看法。在上面的例子中,一个普通的线性模型有系数[20,49,150]。岭回归模型可能具有与普通回归显著不同的系数[1820,23,90]。在实践中,我建议使用一个集合策略来结合来自不同模型的想法。
高度相关特征的诅咒
变量 房间数量 和 平方英尺 是相关的。更大的房子里会有更多的房间。不幸的是,我们不能简单地移除其中一个。相关变量的影响,尤其是共线变量的影响,不容易区分开来。此外,当更改输入数据集时,高度相关的变量可能会导致系数值不稳定。
用 c 进行稳定性检查Ross-验证
为了检查系数的稳定性,一种典型的方法是应用交叉验证,并在循环中跨折叠追踪系数的值。请注意,如果系数在折叠之间变化很大,我们应该谨慎使用它们作为特征重要性。
在本文中,我们以简化的房价预测为例,来解释线性模型中特征重要性的四个经常被忽略但却至关重要的陷阱。如果只有一样东西你会带走,我希望它是清单👍🦖🥊💎🏅:
- 标准化您的数据集
- 不同的模型对特征的重要性有不同的理解
- 小心高度相关的变量
- 应用交叉验证来检查跨折叠系数的稳定性
报名参加🦞:的 Udemy 课程
具有机器学习和统计的推荐系统
机器学习模型中的特征重要性
找到那个(不那么)神奇的特征的方法
来源(去飞溅)
并非所有的特征都是平等的。有些会对你的模型的预测有很大的影响,而有些则不会。在之前的文章中,我们研究了部分依赖的使用,以了解某些特征如何影响预测。确定哪些特征产生最大的预测能力是模型建立过程中的另一个关键步骤。在本文中,我们将研究几种方法来确定哪些特性最有可能产生影响。
特征相关性
我们将使用来自 Kaggle 的这个移动价格分类数据集来说明我们的示例。加载到数据集中后,我们可以做的第一件事是检查我们的特征和我们的目标变量之间的相关性。最简单的方法是使用df.corr()
方法。然而,查看数字网格可能不是可视化数据的最佳方式。相反,我们可以创建一个彩色的热图来检查我们的每个特征是如何与我们的目标变量相关联的。
创建关联热图,同时突出显示我们的目标变量
该热图有效,但是如果我们的数据集中有大量的要素,它可能会迅速增长到难以分析我们的目标变量的大小。我们可以稍微修改一下代码,只关注我们感兴趣的行(包含目标的行)。
简化热图,仅显示我们的目标变量
我们的目标变量的特征相关性
这看起来更干净,更简洁。使用这样的彩色热图可以更容易地看出哪些功能对我们有用。我们可以不看一个充满数字的矩阵,而是看哪些颜色是红色和蓝色的淡色。我们可以立即指出,诸如battery_power
、px_height
、px_width
和ram
等特征都与我们的目标变量price_range
相关。我们现在知道在训练模型时需要注意哪些变量。
记住这一点,让我们转到模型构建,看看这里选择的特性是否真的那么重要。为此,我们将训练一个简单的随机森林模型。训练之后,我们将使用大多数基于树的算法都有的feature_importances_
属性。我们还会将这些值放在数据帧中,以便于分析。
分析模型认为最重要的特征
重要性排名前五的功能
当我们查看由feature_importances_
属性返回的前 5 个特性时,我们可以看到它与我们之前的分析基本一致。返回的数字代表每个特征带来的熵的减少,由我们数据中的样本数归一化。简单地说,返回值越高,这个特性在我们的模型中就越重要。
排列重要性
使用feature_importances_
属性的一种替代方法是所谓的排列重要性。我将使用数据集中的一个例子来解释它是如何工作的。
类似于feature_importances_
属性,排列重要性是在模型适合数据之后计算的。为了说明发生了什么,我们将选取行的子集。
突出显示我们的特征的行的子集
我们在数据集中看到 5 行的子集。我强调了一个具体的特征ram
。我们将随机打乱这一列中的值。这里的预期是,随机重新排列值将对我们的预测产生负面影响。我们感兴趣的是,通过这样做,我们的预测究竟会改变多少。如果我们打乱了一个模型在预测时非常依赖的列(如ram
),那么模型的准确性会比打乱一个不太重要的列(如talk_time
)受到的影响更大。
我们的功能随机洗牌
在改变值之后,我们将再次尝试预测我们的目标变量。通过将这些预测与我们的真实目标值进行比较,我们可以确定我们的损失函数受到了多大程度的混排数据的影响。我们对数据集中的所有要素执行此操作,并比较结果。
谢天谢地,我们不必从头开始。有一个叫做 eli5 的方便的库可以自动为我们完成所有这些工作。让我们看看如何只用几行代码就能使用它。
使用 eli5 库,我们能够快速得出一个排序排列重要性图,如上图所示。我们可以看到,这些数据中的大部分与我们使用相关性和feature_importances_.
进行的初步检查一致,但是我们如何解释这些数据呢?
我们已经知道,靠近顶部的特性对我们的模型最重要,而底部的特性最不重要。显示的第一个数字代表我们的模型的性能由于随机改变特性的值而降低了多少。因为我们是随机调整我们的栏目,所以对我们预测的影响也有随机性的因素。我们可以通过多次重复洗牌过程并观察每次重复的效果如何变化来测量这种随机性。这是我们在+-
之后看到的数字。
你可能也注意到了一件事,我们在底部看到一些特性的负值。这是什么意思?在这种情况下,混乱的数据实际上使我们的预测比真实数据更准确!这意味着该特性并不重要(重要性为 0),但随机移动列恰好使预测更加准确。随机调整数值能给我们更好的预测,这在直觉上说不通。
结论
我们研究了在数据集中识别重要要素的不同方法。我们从特征相关性开始,这发生在我们建立任何模型之前。通过创建彩色热图,我们能够更快地识别重要特征,而无需查看大量数字。
我们看了两种在建立模型后确定特征重要性的方法。在大多数基于树的分类器中发现的 feature_importances_ 属性向我们展示了一个特征对模型预测的影响程度。排列重要性是一种不同的方法,我们将一个特性的值打乱,看看它对我们模型的预测有多大影响。我们能够使用 eli5 库轻松实现这一点。
感谢您的阅读!
您可以通过以下渠道与我联系:
机器学习中的特征选择和 EDA
如何利用数据可视化来指导特征选择
功能选择和 EDA 备忘单(图片由作者提供,来自网站
在机器学习生命周期中,特征选择是选择与预测相关的输入特征子集的关键过程。包含不相关的变量,尤其是那些数据质量差的变量,通常会污染模型输出。
此外,特征选择具有以下优点:
-
避免维数灾难,因为一些算法在高维时表现不佳,例如一般线性模型、决策树
-
降低计算成本以及大量数据带来的复杂性
-
减少过拟合,模型更有可能推广到新数据
-
增加模型的可解释性
在本文中,我们将讨论两种主要的特征选择技术:过滤方法和包装方法,以及如何利用数据可视化来指导决策制定。
数据预处理
在进入特征选择之前,我们应该加载数据集,执行数据预处理和数据转换:
1。加载数据集和导入库
我正在使用来自 Kaggle 的信用卡客户数据集来预测谁更有可能被炒鱿鱼。
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from pandas.api.types import is_string_dtype, is_numeric_dtype df = pd.read_csv("../input/credit-card-customers/BankChurners.csv")
现在让我们看一下原始数据。
信用卡客户数据集(图片由作者提供)
2。定义预测:这个练习是一个分类问题,从中我们预测二元变量“Attrition _ Flag”,它可以是现有客户,也可以是流失的客户。
3。检查缺失数据:
缺失数据(图片由作者提供)
幸运的是,该数据集不包含任何缺失值,但情况并非总是如此。如果您想了解更多关于如何处理丢失数据的信息,这篇文章可能会对您有所帮助。
https://medium.com/analytics-vidhya/how-to-address-missing-data-531ed964e68
4。变量转换:这个过程包括对分类变量进行编码,并将所有变量转换成相同的尺度。我分别选择了标签编码器和最小-最大缩放。
变量转换(图片由作者提供)
如果您想了解更多数据转换技术,请查阅这篇文章:
探索性数据分析
数据可视化和 EDA 是特性选择过程的重要补充工具,可以通过以下方式应用:
- 单变量分析:直方图和条形图有助于可视化每个变量的分布和方差
- 相关性分析:热图便于识别高度相关的解释变量,减少共线性
- 双变量分析:箱线图和分组条形图有助于发现解释变量和响应变量之间的相关性和关系
(为了更好的理解数据,可以在数据转换前进行探索性的数据分析)
单变量分析—直方图和条形图
为了获得分布的概观,首先让我们将特征分类为分类变量和数值变量,然后使用条形图可视化分类特征,使用直方图可视化数值特征。可视化分布给出了关于数据点是更密集还是更分散的建议,从而给出了方差是低还是高的建议。低方差特征往往对结果变量的预测贡献较小。
单变量分析(图片由作者提供)
关联分析—热图
一些算法要求解释变量中没有共线性,包括将用于本练习的逻辑回归。因此,消除高度相关的特征是避免这种潜在缺陷的必要步骤。使用热图可视化的相关性分析突出显示相关系数高的要素对。
相关性分析和热图(图片由作者提供)
如图所示,不难发现以下几对高度相关的特征:
- Customer _ Age&Month _ on _ Book(0.79)
- 合计 _ 交易 _ 金额&合计 _ 交易 _ 金额(0.82)
- Avg _ Open _ To _ Buy&Credit _ Limit(1)
基于这个结果,我放弃了以下变量:
丢弃高度相关的要素
双变量分析—箱线图和分组条形图
双变量 EDA 研究每个解释变量和目标变量之间的关系。分类特征和数值变量分别使用分组条形图和箱线图进行处理,这种探索可以进一步促进过滤方法中使用的统计检验,例如卡方检验和 ANOVA 检验。
G 圆形条形图作为卡方分析 的直观表示
分组条形图代码
每个自变量被设置为主要类别。使用 hue = " attachment _ Flag "将目标变量设置为二级类别。结果,它描述了“损耗 _ 标志”是否会在主要类别的不同级别的分布中变化。如果两个变量是独立的,那么我们期望所有水平的分布是相同的。
这与卡方检验的逻辑相同,卡方检验基于独立性假设计算观察值和期望值之间的差异。如果不存在或存在很少的相关性,我们希望每组条形的比率与流失客户与现有客户的比率成比例。如果比率显著不同,则表明观察值和期望值之间的差异较大,这意味着卡方值较高,因此拒绝了两个变量独立的假设。
根据目标标签绘制所有类别变量后,我发现“Card _ Category”似乎显示了蓝色、金色、银色和铂金的比例变化。在接下来的部分,我们将根据基于过滤方法的定量评分来了解这是否属实。
分组条形图结果(作者图片)
方框图用作方差分析的直观表示
箱线图代码
箱形图显示数字数据组通过其分位数的分布。每个方框显示数据在组内的分布情况,并排放置方框表示各组之间的差异。它与 ANOVA 测试一致,ANOVA 测试也分析组间与组内相比的差异程度。如果相对可变性较大,例如下面所示的 "Total_Revolving_Bal" 和 "Total_Cnt_Chng_Q4_Q1" ,则可能表明这些特征可能有助于预测标签。让我们看看这是否可以通过过滤方法中的 ANOVA 测试来量化。
箱线图结果(图片由作者提供)
箱线图结果(图片由作者提供)
如果你想对 EDA 有更透彻的了解,可以随意阅读我的文章《Python 中的半自动探索性数据分析(EDA)》。
特征选择
如果你想更深入地了解特征选择的重要性和实现特征选择的不同技术,下面来自 neptune.ai 的博客提供了全面的指导。
https://neptune.ai/blog/feature-selection-methods
在本文中,我们将主要介绍两类特征选择方法:过滤方法和包装方法。根本区别在于,过滤方法基于卡方、方差分析等统计测试评估特征重要性,而包装方法基于这些特征生成的模型的性能迭代评估特征子集的性能。
过滤方法
过滤方法图解(图片由作者提供)
过滤方法通过评估每个特征与因变量的关系来给每个特征打分。对于具有分类响应变量的分类问题,我使用这三个主要的评分函数:卡方(score_func = chi2)、ANOVA (score_func = f_classif)和互信息(score_func = mutual_info_classif)。要创建一个特征选择模型,我们需要 SelectKBest() 函数,然后指定要使用的评分函数以及要选择的变量数量。
selection_model = SelectKBest(score_func=score_function, k=variable_counts)
我想知道这两个参数,评分函数和变量的数量,将如何影响在所选特征上训练的模型的准确性。
首先,为了创建并执行特征选择,并检查在此基础上构建的模型的性能,我定义了一个 feature_selection 函数,步骤如下:
- 导入所需的库
- 基于两个参数创建特征选择模型:score_function(例如,卡方)和变量计数(例如,范围从 1 到所有特征)
- 仅基于所选特征训练逻辑回归模型
- 计算准确性分数
导入库
定义特征选择函数
其次,为了测试得分函数和变量计数如何影响模型性能,我使用下面的代码迭代地传递两个参数的不同组合, "variable_counts" 和 "score_function ",。
过滤方法准确度图表代码
数据可视化过滤方法
结果以数据框格式生成,然后使用折线图展示精度如何随着所选要素数量的增加而提高。如图所示,除了互信息方法,准确率评分在达到 8 个特征后稳定在 0.88 左右。
过滤方法准确性(图片由作者提供)
之后,让我们调查基于各种方法的每个特征的得分是多少。这一次,我们将使用条形图来直观显示根据卡方、方差分析或互信息分配给特征的分数。
特征分数代码
不同统计的特征分数(按作者的图像)
正如你所看到的,不同的方法对相同的特性有不同的评分,但是有些特性总是出现在列表的较高位置。例如, "Total_Revolving_Bal" 总是位于前 3 位,这与二元 EDA 中的箱线图的结果一致。与其他分类变量相比,“Card_Category”确实具有较高的特征重要性,这可以通过分组条形图来解释。
包装方法
包装方法说明(图片由作者提供)
包装器方法通过评估基于这些特征训练的机器学习模型的性能来寻找最优的特征子集。因为它将模型结合到特征选择过程中,所以它需要更多的计算能力。本文介绍了两种主要的包装器方法,向前选择和向后消除。为了执行向前选择和向后排除,我们需要SequentialFeatureSelector()函数,该函数主要需要四个参数:
- 模型:对于分类问题,我们可以使用逻辑回归、KNN 等,对于回归问题,我们可以使用线性回归等
- k_features:要选择的特征的数量
- 向前:确定是向前选择还是向后排除
- 评分:确定模型性能的评估指标,例如分类问题——准确度、精确度、召回率等;回归问题— p 值、R 平方等
正向选择
正向选择从模型中没有特征开始,一次向特征子集中增加一个特征。在每次迭代期间,基于由特征子集训练的模型的评估来选择新特征。
由于机器学习模型包含在特征选择算法中,我们需要指定一个模型作为输入参数之一。对于这个分类问题,我选择了逻辑回归,并以准确率作为评价指标。与筛选方法相比,包装方法在计算精确度方面略有不同。由于我们只使训练集适合包装器模型,所以包装器方法本身返回的准确度分数完全基于训练数据集。因此,有必要在所选特征上训练附加模型,并基于测试集进一步评估。
为此,我使用下面的代码来导入所需的库,并创建和评估基于包装方法构建的逻辑回归模型。
导入库
正向选择代码
落后淘汰
简单来说,就是和正向选择正好相反,从包含所有特征开始训练模型。然后,基于特征是否对模型性能有贡献,从特征子集中迭代地移除特征。类似地,逻辑回归和准确度被相应地用作模型和评估度量。
反向选择码
包装方法和数据可视化
与 filter 方法类似,我将向前选择和向后排除都封装到一个“for 循环”中,以便检查变量计数是否会影响准确性分数。
包装方法准确性代码
如折线图所示,当特征计数小于 4 时,准确度快速增长,然后在 0.88 左右保持稳定。
包装方法准确性图表(图片由作者提供)
在该数据集中,由于总共只有大约 20 个要素,因此要素选择可能很难对模型性能产生任何重大影响。然而,不可否认的是,数据可视化可以帮助我们决定哪些特征和多少特征适合数据集或目标。这一原则肯定可以扩展到具有更多变量的其他数据集。
带回家的信息
本文涵盖了两种基本的特性选择技术:
- 过滤方法:基于卡方、ANVOA 和互信息
- 包装方法:基于正向选择和反向淘汰
我们还将了解如何使用数据可视化来更好地理解要素属性,以及如何选择适当数量的要素。
更多这样的文章
https://neptune.ai/blog/feature-selection-methods
原载于 2021 年 5 月 24 日 https://www.visual-design.net**。
功能选择—穷举与精选
人工智能笔记
数据科学中一个哲学难题的答案
由 Giammarco Boscaro 在 Unsplash 上拍摄的照片
这是数据科学中的一个哲学困境。我们应该使用什么样的特征选择方法:精选的还是穷举的?答案是“看情况”。在这里,“精选”意味着选择一小组有意义的特征,这些特征可以被很好地解释;“详尽”意味着选择数据集中所有可能的要素组合。我来自相信过度复杂没有帮助的 ML 专家部落,至少在大多数情况下。说你可能会认为我是一个樱桃采摘法的粉丝。然而,这并不完全正确。在本文中,我想比较这两种特性选择方法,并帮助您决定应该在哪里选择它们。我解释了几个场景的不同之处,以帮助您确定如何为自己的项目选择特性选择方法。
我决定写这篇文章,在收到许多关于我的前一篇文章的积极反馈之后,这篇文章的标题是构建一个 ML 产品——避免的 4 个错误,在那里我分享了一些见解,以防止在构建一个 ML 产品时的常见错误。
可解释与不可解释
- 场景 1 :“你在一家大型企业从事数据科学项目。你的经理和其他利益相关者对机器学习及其潜力没有深入的了解。他们不仅要求你通过这个项目创造价值,还要让他们相信整个解决方案。因为他们不能很好地理解你,所以你有挫败感。”
如果你使用可解释的特征,也就是那些可以被问题的物理学支持的特征,你可以更容易地获得对组织的信任。这并不意味着您不应该在您的项目中应用详尽的特性选择技术。然而,整个机器学习管道还没有准备好,你必须向其他利益相关者展示初步结果。如果你选择植根于问题物理的可解释特征,你可以更好地与其他团队成员交流,更容易支持你的决策。因此,当您处理场景 1 时,我建议从精选的特征选择方法开始。
早期与晚期
- 情景二:“你在一家早期的创业公司工作。你遇到许多截止日期,必须向投资者或在竞争中演示产品。你需要建立一个运行良好的机器学习模型。对模型性能的期望还不高,任何功能性 ML 模型都会受到赞赏。”
你可能认为在这种情况下穷举方法更好,因为你没有时间做特性工程等等。我不同意!尤其是在早期,你需要很多技巧来应对各种情况。如果你使用详尽的方法,你对过程没有足够的了解,因此,不能对早期阶段经常出现的意外情况做出快速反应。因此,我建议在发展的早期阶段进行精心挑选,在发展的后期阶段进行彻底挑选。
洞察导向与结果导向
- 场景 3 :“你正在从事一个数据科学项目,其主要目标是深入了解问题。ML 模型的结果很重要,但更重要的是,您必须提供建议来增强您所分析的过程。你的表现不是用 ML 模型的数字结果来衡量的。事实上,您负责创建一个由 ML 模型支持的建议列表,这些建议可以改进业务逻辑和流程。”
例如,您使用机器学习模型来预测制造过程中的回报率。这个过程如此复杂,以至于没有人对它有足够的了解。所以,你不应该增加它的复杂性。反过来,你必须通过创建一个可操作的提示列表来帮助企业主更深入地了解制造过程。这里推荐使用精选方法,因为它提供了可见性。ML 管道在其他地方已经足够复杂,你不应该故意增加它的复杂性。
外卖食品
简而言之,在我看来,你必须始终以精挑细选的方式开始一个数据科学项目。然后,当你(a)洞察到问题,(b)与其他利益相关者建立信任,以及(c)开发一个可靠的 ML 管道时,你就可以切换到穷举方法。特征选择中的详尽方法使您能够在数据允许的情况下尽可能提高模型性能。
感谢阅读!
如果你喜欢这个帖子,想支持我…
https://pedram-ataee.medium.com/membership
预测算法的特征选择
不保证这些功能能够提高预测性能。在这篇文章中,我们解释了为什么,以及如何执行特征选择。
在本文中,我们讨论预测的特征选择。我们首先解释为什么你应该三思而后行添加功能到您的预测;然后,我们讨论一些为预测模型进行特征选择的方法。实际上,在R
中,我们演示了一种在性能和计算成本之间取得平衡的特性选择方法。
为什么在预测模型中包含特性之前要三思?
对于许多数据科学模型来说,特征越多(通常指预测中的回归量),您的模型准确性就越好。但是预测是相当有限的,而事实往往并非如此。
这是为什么呢?
我们将把它分成几点。
- 假设你想预测一个硬币是正面还是反面。那是不可能的。这是因为你试图预测的变量(姑且称之为目标)是完全随机的。有些目标根本没有任何信号,或者没有提供任何信号的回归量。
- 让我们称这个变量的观察值为实际值。这些通常已经包含了惊人的信息量。你所使用的预测算法会不顾一切地捕捉这个信号。这意味着你的特性不仅仅必须与目标相关,它还必须提供现实中没有的信息。这是非常罕见的。例如,冰淇淋销售将与天气相关,但它肯定不会包含比实际更多的信息。
- 你要么需要提前知道你的回归变量(它需要面向),要么你也需要预测那个回归变量。回到冰淇淋的例子,这个回归量不是面向前的。所以,如果你想知道一周以后的天气,你必须提前一周预测冰激凌的销量,然后把它输入到你的预测算法中。这给你的回归变量增加了很多噪音,反过来又给你的预测增加了噪音,使它变得更糟。这很少值得去做。
- 即使是前向回归,也经常会在你的预测中加入意想不到的噪音,只是因为没有足够的信号,类似于第 1 点和第 2 点。
罗斯·斯奈登在 Unsplash 上的照片
为预测算法执行特征选择的一些方法
有几种方法可以检查回归变量是否为预测提供了有用的信息。其中大多数依赖于前向回溯测试。前向回溯测试是从一个历史日期(称为最新数据)开始,仅使用截至该日期的数据进行预测,然后移动到下一个日期并重复,直到到达现在。
然后,为了评估您的预测,您可以计算与实际值相比的预测误差。因此,这很像经典数据科学问题中的训练/测试集分裂。这个技术的教程是这里。如果您有两个预测想要在其中做出选择,您可以对每个预测进行回溯测试。误差最小的那个将被归类为最好的。
有了这些,以下是一些执行特征选择的方法,按计算和时间成本增加的顺序排列:
1.查看实际值和回归量之间的相关性。
这只是使用样本内拟合来检查回归变量,并不包括上一节中的第 2 点(回归变量是否包含预测不包含的信息)。不建议使用此选项。
2.使用预测的赤池信息标准(AIC)。
这是一种统计近似值,试图使用样本拟合来近似预测拟合。参见本章使用 AIC 进行选型。
其工作方式是,在有和没有回归变量的情况下,您都要拟合您的预测模型,并检查每个模型的 AIC。你会选择 AIC 最低的型号。
这种方法好,快,常用。但这是一个仅使用样本拟合的近似值,因此可能无法很好地估计预测拟合。
3.对实际值使用线性回归,将当前预测和您的回归量作为一个特征
这个方法的关键是绕过第二点。我们想检查在考虑了预测已经了解的信息之后,回归变量给出了多少额外的预测信息。
对于这种方法,我们使用当前预测进行单次回溯测试,不使用回归变量。然后,我们通过试图了解实际情况的线性回归来输入回归变量和预测值。
为了评估回归变量有多好,我们可以用评估线性回归的标准方法检查回归变量是否显著(即检查其 p 值是否足够小)。因为我们还将预测本身包括在回归中,所以这种回归应该考虑预测算法已经学习到的内容。
这种方法直接评估预测拟合,但只需要运行一次回溯测试。当您有许多回归变量要检查时,这种方法特别有效。您仍然只需要进行一次回溯测试(没有回归变量的当前预测),然后您可以在线性回归中使用标准的模型选择技术,例如递归特征消除(确保您没有消除您的预测)!
4.使用和不使用回归变量运行预测回溯测试
这种方法很简单,我们使用回归预测和不使用回归预测来进行回溯测试。然后我们比较两者的误差。如果回归变量的预测误差明显较低,我们可以继续使用该回归变量。
回溯测试是预测中模型选择的基础。所以这个方法效果很好。
但是随着回归量的增加,这种方法变得非常昂贵。我们必须在每辆列车上安装多个预测模型。
演示方法 3
我们选择演示方法 3,因为它在直接测量回归变量的预测质量和计算成本之间提供了良好的平衡。通常,对迄今为止最佳预测方法的回溯测试已经从其他实验中获得,这是这种方法中计算量最大的部分。
为了实际演示,我们将使用R
。在 my github 上跟随本教程的互动 Rmarkdown 。对于本教程中使用的所有包,通过运行R
install.packages('fpp3')
下载 FPP3 包。这个软件包是 Rob Hyndman 的介绍性预测书的伴侣。
我们将使用的数据是书中的美国消费支出数据。这是美国经济中各种措施的季度百分比变化的时间序列。我们有兴趣预测的是经济产量,这是衡量美国经济健康程度的一个指标。在fpp3
加载后可以访问,称为us_change
。我们要预测的栏目是Production
。让我们画出来
library(fpp3)
us_change %>%
autoplot(Production) +
labs(y = "Production (% change)")
产量随时间变化的百分比图。
为了预测该数据,我们将为该数据拟合一个 ARIMA 模型,这允许添加回归变量。
为了对我们需要检查的特征进行线性回归,我们需要在没有回归量的情况下对我们的预测算法进行回溯测试。让我们对最近 50 个数据点的预测模型进行回溯测试,并提前一步进行预测。ARIMA
功能将使用 AIC 自动执行 ARIMA 模型的参数调整。
# Set seed for reproducibility
set.seed(13)
backtest_size <- 50
n <- nrow(us_change)
backtest_results <- us_change[(n - (backtest_size - 1)):n,]
backtest_results$forecast <- rep(NA, backtest_size)
for (backtest_num in backtest_size:1) {
fit <- us_change[1:(n - backtest_num),] %>%
select(Production) %>%
model(
forecast = ARIMA(Production)
)
backtest_fc <- fit %>% forecast(h = 1)
results_index <- backtest_size - (backtest_num - 1)
backtest_results$forecast[results_index] <- backtest_fc$.mean
}
# Let’s plot our backtest results against actuals
backtest_results %>%
pivot_longer(c(Production, forecast), names_to = "Type") %>%
autoplot(value)
无回归变量的 ARIMA 回测图。
请注意,预测在正常期间表现良好,但在大幅波动期间表现不佳。我们能使用回归变量来改善这一点吗?
我们对生产数据进行了建模,生产数据通常用 GDP 来衡量。但是衡量 GDP 需要付出巨大的努力,在许多国家,每季度才进行一次。其他数据可能更容易定期估算,也更容易获得。衡量这一点的一个标准可能是消费者支出。这是我们数据集中的Consumption
列。
让我们用一个简单的线性回归来看看用消费作为回归变量有没有前途。
regress_test <- lm(Production ~ forecast + Consumption, data = backtest_results)
summary(regress_test)
##
## Call:
## lm(formula = Production ~ forecast + Consumption, data = backtest_results)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.4347 -0.7459 0.1566 0.5379 2.4470
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.8588 0.1889 -4.545 3.84e-05 ***
## forecast 0.8750 0.1406 6.224 1.23e-07 ***
## Consumption 1.2630 0.3158 4.000 0.000223 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.9268 on 47 degrees of freedom
## Multiple R-squared: 0.6461, Adjusted R-squared: 0.6311
## F-statistic: 42.91 on 2 and 47 DF, p-value: 2.501e-11
对于Consumption
列,p 值非常低,远低于经典的 0.05 水平。这表明将其包括在预测中会提高预测性能。
消费者储蓄呢(数据集中的Savings
列)?
regress_test_savings <- lm(Production ~ forecast + Savings, data = backtest_results)
summary(regress_test_savings)
##
## Call:
## lm(formula = Production ~ forecast + Savings, data = backtest_results)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.1353 -0.5435 0.1223 0.6092 2.7229
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.34043 0.16657 -2.044 0.0466 *
## forecast 1.08637 0.14867 7.307 2.8e-09 ***
## Savings -0.01165 0.01029 -1.132 0.2633
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.059 on 47 degrees of freedom
## Multiple R-squared: 0.5383, Adjusted R-squared: 0.5186
## F-statistic: 27.39 on 2 and 47 DF, p-value: 1.299e-08
这种情况下的 p 值很高,因此我们不应该在模型中包括储蓄。
让我们通过将消费纳入 ARIMA 模型并运行新的回溯测试来检查我们的选择
backtest_regressor_results <- backtest_results
backtest_regressor_results$forecast_consumption <- rep(NA, backtest_size)
for (backtest_num in backtest_size:1) {
fit <- us_change[1:(n - backtest_num),] %>%
select(Quarter, Production, Consumption) %>%
model(
forecast = ARIMA(Production ~ Consumption)
)
new_regressor <- select(us_change[n - (backtest_num - 1),], Quarter, Consumption)
backtest_fc <- fit %>% forecast(new_data = new_regressor)
results_index <- backtest_size - (backtest_num - 1)
backtest_regressor_results$forecast_consumption[results_index] <- backtest_fc$.mean
}
# Plot both backtests
backtest_regressor_results %>%
pivot_longer(c(Production, forecast, forecast_consumption), names_to = "Type") %>%
autoplot(value)
有和没有选定回归量的 ARIMA 回测图。
凭肉眼判断哪个预测表现更好有点困难,所以让我们检查一下 MSE 误差
backtest_regressor_results %>%
as_tibble() %>%
summarise(
MSE_no_regressors = mean((Production - forecast)^2),
MSE_consumption_regressor = mean((Production - forecast_consumption)^2)
)
## # A tibble: 1 x 2
## MSE_no_regressors MSE_consumption_regressor
## <dbl> <dbl>
## 1 1.20 1.01
在包括消费作为回归变量的后验测试中,MSE 较低,因此我们可能做出了正确的选择:)。
要点
- 在预测中,包含功能并不能保证会提高模型性能,因此在这样做之前要仔细考虑。
- 预测中的特征选择是选择性能和计算成本之间的折衷。
- 在预测中选择直接衡量预测性能的功能的一种方法是,在没有回归变量的情况下对预测进行回溯测试,然后拟合线性回归模型,以了解给定预测和回归变量的实际情况。如果 p 值较低,选择回归变量。
原载于 2021 年 8 月 23 日 https://jackbakerds.comhttps://jackbakerds.com/posts/forecasting-feature-selection/。
机器学习的特征选择:3 类 12 种方法
图片由 Faye Cornish 在 Unsplash 上拍摄
这篇文章的大部分内容来自我最近的一篇题为:
“环境数据特征选择方法的评估”的论文,任何感兴趣的人都可以在这里获得。
降维的两种方法
有两种方法来减少特征的数量,也就是所谓的降维。
第一种方式被称为特征提取,其目的是转换特征并基于原始/给定特征的组合创建全新的特征。
最流行的方法是主成分分析、线性判别分析和多维标度。然而,新的特征空间几乎不能为我们提供关于原始特征的有用信息。新的更高层次的特征不容易被人类理解,因为我们不能将它们直接与初始特征联系起来,从而难以得出结论和解释变量。
第二种降维方式是特征选择。
它可以被认为是一个预处理步骤,并且不创建任何新特征,而是选择原始特征的一个子集,提供更好的可解释性。
从一个有意义的初始数字中找到最佳特征可以帮助我们提取有价值的信息发现新知识。
在分类问题中,特征的重要性根据其解决不同类别的能力进行评估。
给出每个特征在区分不同类别中的便利性的估计的属性被称为特征相关性。
特征选择的目标
特征选择有许多目标。
1。它通过保留与目标变量具有最小冗余和最大相关性的特征来消除 不相关和有噪声的特征。
2。它减少了训练和测试分类器的计算时间和复杂性,因此它产生了更具成本效益的模型。
3。它提高学习算法的性能,避免过度拟合,并有助于创建更好的通用模型。
3 种特征选择方法
根据它们与分类器的交互方式,有三类特征选择方法,即过滤器、包装器和嵌入式方法。
过滤方法是可扩展的(直到非常高维的数据),并且在分类之前执行快速特征选择,使得学习算法的偏差不会与特征选择算法的偏差相互作用。他们主要充当排序者,将特性从最好到最差排序。
特征的排序取决于数据的内在属性,例如,方差、一致性、距离、信息、相关性等。
存在许多过滤方法,新的方法也在不断发展,每种方法都使用不同的标准来衡量数据的相关性。
相关性的一个通用定义是,如果一个特征有条件地独立于类别标签或者不影响类别标签,则该特征可以被认为是不相关的;在这些情况下,它可以被丢弃。
包装器方法使用机器学习算法作为黑盒评估器来寻找特征的最佳子集,因此,它们依赖于分类器。
实际上,搜索策略和建模算法的任何组合都可以用作包装器。
当在具有大量特征的数据集中执行包装时,它会消耗额外的计算资源和运行时间。
最后,这些方法实现起来很简单,并且可以对特征依赖进行建模。
嵌入式方法 在过滤器和包装器之间架起了桥梁。首先,他们像过滤器一样融合可测量和统计标准来选择一些特征,然后使用机器学习算法,选择具有最佳分类性能的子集。
它们降低了包装器的计算复杂度,无需在每次迭代中对子集进行重新分类,并且可以对特征依赖性进行建模。他们不执行迭代。
特征选择在学习阶段进行,这意味着这些方法同时实现了模型拟合和特征选择。一个缺点是它们依赖于分类器。
过滤方法
1.卡方检验
基于常用χ统计检验的单变量过滤器,用于测量与预期分布的偏差(如果假设要素的出现实际上与类值无关)。
像任何单变量方法一样,我们计算每个特征和目标变量之间的卡方,并观察它们之间的关系。
如果目标变量与特征无关,则得分较低,或者如果它们是相关的,则特征很重要。
卡方值越高,表示要素与类别的相关性越高。
要使用该方法,安装 scikit-learn 。
对于所有代码示例,我们假设 X 是特性的熊猫数据框架,y 是目标的熊猫系列。
!pip install scikit-learn
from sklearn.feature_selection import chi2
X_norm = MinMaxScaler().fit_transform(X)
chi_selector = SelectKBest(chi2, k='all')
chi_selector.fit(X_norm, y)
2.交互信息
这个方法就是一个滤波器,也叫信息增益。
它是最流行和最常用的单变量特征选择方法之一,因为它的计算速度和简单的公式。
它测量每次考虑单个特征时熵的减少。
如果一个特征具有高信息增益,则该特征被认为是相关的。
它不能处理冗余特征,因为特征是以单变量方式选择的。
因此,它属于“近视”方法,在这种方法中,独立地评估特征而不考虑它们的上下文。
要使用该方法,安装 scikit-learn 。
!pip install scikit-learn
from sklearn.feature_selection import mutual_info_classif
mi_selector = SelectKBest(mutual_info_classif, k='all')
mi_selector.fit(X, y)
3.方差分析 F 值
这是一种单变量过滤方法,使用方差来找出类之间的个体特征的可分性。
适用于多类端点。
要使用该方法,安装 scikit-learn 。
!pip install scikit-learn
from sklearn.feature_selection import f_classif
anov_selector = SelectKBest(f_classif, k='all')
anov_selector.fit(X, y)
4.方差阈值
这种过滤方法并不总是被认为是一种要素选择方法,因为它的标准并不是在每个数据集中都能满足。
移除变化低于某个截止值的特征。这个想法是,当一个特征在样本间变化不大时,它通常没有什么预测能力。
要使用该方法,安装 scikit-learn 。
!pip install scikit-learn
from sklearn.feature_selection import VarianceThreshold
var_selector = VarianceThreshold(*threshold=*0)
var_selector.fit_transform(X)
5.费希尔评分
这是一种使用均值和方差对要素进行分级的过滤方法。相同类的实例中具有相似值而不同类的实例中具有不同值的特征被认为是最佳的。与之前的单变量方法一样,它单独评估特征,并且它不能处理特征冗余。
要使用该方法,请安装 skfeature-chappers。
!pip install skfeature-chappers
from skfeature.function.similarity_based import fisher_score
score = fisher_score.fisher_score(X.to_numpy(), y.to_numpy())
6.多重表面
它是一种扩展的 ReliefF 及其多类扩展 ReliefF 滤波器的特征选择方法。
原始 relief 的工作方式是从数据集中随机抽取一个
实例,然后从
相同和相反的类中定位其最近的邻居。
将最近邻属性的值与采样实例进行比较,以更新每个属性的相关性分数。
基本原理是一个有用的属性应该区分来自不同类的实例,并且对于来自相同类的实例应该有相同的值。
在所有 relief 扩展中,MultiSURF 在各种问题类型中提供了最可靠的特征选择性能。
要使用该方法,请安装 skrebate 。
!pip install skrebate
from skrebate import MultiSURF
fs = MultiSURF(n_jobs=-1, n_features_to_select=featureCutoff)
fs.fit(X.values, y.values)
包装方法
1.递归特征消除
这种广泛使用的包装方法使用一种算法来迭代地训练模型,并且每次都使用算法的权重作为标准来移除最不重要的特征。
这是一种多变量方法,它评估共同考虑的几个特征的相关性。
当用作排序器时,在每次迭代中,被移除的特性被添加到堆栈中,直到所有特性都被测试。
为了提高计算效率,可以在单个步骤中移除多个特征。
这种方法计算速度慢。
要使用该方法,安装 scikit-learn 。
!pip install scikit-learn
from sklearn.feature_selection import RFE
rfe_selector = RFE(estimator=LogisticRegression(),
n_features_to_select=1, step=1, verbose=-1)
rfe_selector.fit(X_norm, y)
2.排列重要性
排列重要性是一种用于规范化特征重要性度量的启发式方法,可以纠正特征重要性偏差。
该方法基于结果向量的重复排列,用于
估算非信息环境中每个变量的测量重要性分布。
观察到的重要性的 p 值提供了特征重要性的校正度量。
要使用该方法,安装 scikit-learn 和 eli5 。使用选择的算法。这里我使用了逻辑回归。
!pip install eli5
!pip install scikit-learn
from eli5.sklearn import PermutationImportance
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
perm = PermutationImportance(LogisticRegression(), random_state=42, cv=10)
perm.fit(X, y)
perm_selector = SelectFromModel(perm,max_features=featureCutoff).fit(X, y)
3.SHAP
SHapley 附加解释是一种解释任何机器学习模型输出的统一方法。
它将博弈论与局部解释联系起来,联合了以前的几种方法,代表了唯一可能一致且局部精确的基于期望的加性特征归因方法。
近年来已经成为事实上的特征选择方法。
要使用该方法,安装shap**并使用选择的算法。这里我用了 xgboost。
*!pip install shap
import shap
import xgboost
model = xgboost.train({"learning_rate": 0.01}, xgboost.DMatrix(X, label=y), 100)
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X)*
4.博鲁塔
设计为随机森林包装器的算法。
它迭代地移除被统计测试证明为不如随机探针相关的特征
要使用该方法,请安装Boruta并使用算法。这里我使用随机森林。
**!pip install Boruta
from boruta import BorutaPy
rf = RandomForestClassifier(n_jobs=-1, class_weight='balanced', max_depth=5)
boru_selector = BorutaPy(rf, n_estimators='auto', verbose=0, random_state=1)
boru_selector.fit(X.values, y.values)**
嵌入式方法
1.嵌入式随机森林
这种嵌入式特征选择使用随机森林算法。
通过随机置换出袋样本中的特征,并计算与所有变量保持不变的出袋率相比,误分类率的增加百分比,来测量特征的重要性。
要使用该方法,安装 scikit-learn 。
**!pip install scikit-learn
from sklearn.feature_selection SelectFromModel
from sklearn.ensemble import RandomForestClassifier
embeded_rf_selector = SelectFromModel(RandomForestClassifier(n_estimators=100, random_state=42), max_features=featureCutoff)
embeded_rf_selector.fit(X, y)**
2.嵌入式 LightGBM
这种嵌入式特征选择使用流行的 LGB 算法。
要使用该方法,安装 scikit-learn 和 lightgbm 。
**!pip install lightgbm
from lightgbm import LGBMClassifier
from sklearn.feature_selection SelectFromModel
lgbc=LGBMClassifier(n_estimators=500, learning_rate=0.05,
num_leaves=32, colsample_bytree=0.2,
reg_alpha=3, reg_lambda=1, min_split_gain=0.01,
min_child_weight=40)
embeded_lgb_selector = SelectFromModel(lgbc, max_features=featureCutoff)
embeded_lgb_selector.fit(X, y)**
不确定接下来要读什么?这里有两个选择:
**
保持联络
跟随我在 Medium 上获取更多类似的内容。
我们在 LinkedIn 上连线吧。
检查我的 GitHub 。**
特征选择:如何丢弃 95%的特征并获得 95%的准确率
特征选择是数据管道中的一个基本步骤。一个例子?在 MNIST 数据集上,只需要 40 个像素(总共 784 个像素)就可以获得 95%以上的准确率(99% ROC)。
[作者图]
1.为什么选择功能?
你能认出这些手写的数字吗?
一些 MNIST 数字后,删除 75%的图像。[作者图]
你可能很容易就能分别识别 0、3 和 8。
如果是这样的话,即使只显示了原始图像的 25%,而剩余的 75%被红色像素覆盖,你也能够正确地对它们进行分类。这是一个简单的任务,因为“相关的”像素是可见的,而只有“不相关的”和“多余的”像素被隐藏。
这是“特征选择”的一个简单例子。
特征选择是在机器学习中执行的过程,在将数据馈送到预测模型之前,移除一些特征。如果数据是表格的形式,这仅仅意味着从表格中删除许多列。
为什么要费心选择功能呢?我就不能把所有的数据都扔进我的预测模型里,让他来干脏活吗?
实际上,有几个原因可以让您进行特征选择:
- 记忆。大数据占用大空间。删除要素意味着需要更少的内存来处理数据。有时还存在外部约束(例如,Google 的 AutoML 允许您使用不超过 1000 列的。因此,如果您有超过 1000 列,您将被迫只保留其中的一部分)。
- 时间。用更少的数据训练一个模型可以节省你很多时间。
- 精度。少即是多:这也适用于机器学习。包括冗余或不相关的特征意味着包括不必要的噪声。通常,根据较少数据训练的模型表现更好。
- 可解释性。更小的模型也意味着更易解释的模型。想象一下,如果你不得不解释一个基于成千上万不同因素的模型:这是不可行的。
- 调试。较小的型号更容易维护和排除故障。
2.从数据开始
在本文中,我们将比较一些特征选择的方法。我们的操场数据集将是世界闻名的“MNIST”。
MNIST 是由 70,000 张手写数字的黑白图像组成的数据集。每幅图像都是 28 x 28 (= 784)像素。每个像素被编码为从 1(白色)到 255(黑色)的整数:该值越高,颜色越深。按照惯例,60,000 幅图像用作训练集,10,000 幅图像用作测试集。
可以通过 Keras 命令将数据导入 Python(我们还将重塑数据集,使其成为二维表格):
from keras.datasets import mnist(X_train, y_train), (X_test, y_test) = mnist.load_data()X_train = X_train.reshape(60000, 28 * 28)
X_test = X_test.reshape(10000, 28 * 28)
例如,让我们打印出第 8 行的值:
print(X_train[7, :])
这是结果:
MNIST 训练数据集的第 8 幅图像的所有 784 个像素。[作者图]
通过 Matplotlib,我们还可以显示相应的图像:
import matplotlib.pyplot as pltplt.imshow(X_train[7, :].reshape(28, 28), cmap = 'binary', vmin = 0, vmax = 255)
MNIST 训练数据集的第 8 幅图像。
3.特征选择之战
我们的任务是选择少量的列(即像素),这些列在输入预测模型时足以达到良好的精度水平。
有许多可能的策略和算法来执行特征选择。在本文中,我们将测试其中的 6 个:
3.1 F 统计量
f 检验是方差分析 f 检验的结果。该检验计算为比率:组间变异性 / 组内变异性,其中组为目标类。
其思想是,当组(0 类图像、1 类图像、…、9 类图像)之间的可变性高而同一组内的可变性低时,像素是相关的。
from sklearn.feature_selection import f_classiff = f_classif(X_train, y_train)[0]
3.2 相互信息
互信息是两个变量之间相互依赖的度量。
由于 MI 的公式需要知道每个变量的概率分布(通常我们不知道分布),因此 scikit-learn 实现采用了基于 k 最近邻距离的非参数近似。
from sklearn.feature_selection import mutual_info_classifmi = mutual_info_classif(X_train, y_train)
3.3 逻辑回归
如果目标变量是分类的(如我们的情况),可以对数据进行逻辑回归。然后,这些特征的相对重要性可以被用来从最相关到最不相关对它们进行排序。
from sklearn.linear_model import LogisticRegressionlogreg = LogisticRegression().fit(X_train, y_train)
3.4 灯 GBM
任何预测模型都可以做到这一点。比如 LightGBM。
from lightgbm import LGBMClassifierlgbm = LGBMClassifier(
objective = 'multiclass',
metric = 'multi_logloss',
importance_type = 'gain'
).fit(X_train, y_train)
3.5 博鲁塔
Boruta 是 2010 年作为 r 的一个包设计的一个优雅的算法。Boruta 的目的是告诉每个特征是否与目标变量有某种关系。所以,Boruta 的输出更多的是每个特性的是/否,而不是特性的排序。
(如果你很好奇想知道更多关于 Boruta 的功能,我写了一篇关于它的帖子: Boruta 准确地解释了你希望别人如何向你解释)。
from boruta import BorutaPy
from sklearn.ensemble import RandomForestClassifierboruta = BorutaPy(
estimator = RandomForestClassifier(max_depth = 5),
n_estimators = 'auto',
max_iter = 100
).fit(X_train, y_train)
3.6 MRMR
MRMR(代表“最大相关性最小冗余”)是在 2005 年设计的用于特征选择的算法。MRMR 背后的想法是识别与目标变量高度相关且彼此冗余度较小的特征子集。
(如果你很想知道更多关于 MRMR 的运作,我写了一篇关于它的帖子: MRMR 准确地解释了你希望别人如何向你解释)。
from mrmr import mrmr_classifmrmr = mrmr_classif(X_train, y_train)
所有这些算法都提供了特征的“排序”(除了 Boruta,它有一个是/否的结果)。我们来看看根据算法的不同,排名是如何变化的。
MNIST。根据不同的算法,像素按其相关性排序。[作者图]
4.哪种方法效果更好?
此时,一个自然的问题是:
特征选择应该选择什么方法?
在数据科学中,最好的选择是测试不同的方法,看看哪种方法能更好地处理数据。因此,让我们在 MNIST 身上试试吧。
我们将采用 5 种方法提供的特征排名(因为 Boruta 不提供排名),并查看在前 K 个特征上训练预测模型时可以达到什么精度(对于最高达 40 的 K )。
import pandas as pd
from catboost import CatBoostClassifier
from sklearn.metrics import accuracy_scorealgos = ['f', 'mi', 'logreg', 'lightgbm', 'mrmr']
ks = [1, 2, 5, 10, 15, 20, 30, 40]
accuracy = pd.DataFrame(index = ks, columns = algos)for algo in algos:
for nfeats in ks: feats = ranking[algo][:n_feats]
clf = CatBoostClassifier().fit(
X_train[:, feats], y_train,
eval_set = (X_test[:, feats], y_test),
early_stopping_rounds = 20
)
accuracy.loc[k, algo] = accuracy_score(
y_true = y_test, y_pred = clf.predict(X_test[:, cols])))
这些是结果:
在前 K 个特征上训练的预测模型的准确性,K 高达 40。[作者图]
在这种情况下, MRMR 胜过了其他算法。
如图所示,在 MRMR 识别的最相关的 40 个像素上训练的预测器在测试图像上达到 95.54%的准确度!
这令人印象深刻,尤其是考虑到:
- 40 像素只是整个图像(由 28 x 28 = 784 个像素组成)的 5%;
- 我们使用了一个预测模型(CatBoost ),没有进一步的调整,因此这个性能可能还可以进一步提高。
因此,在 MNIST 的情况下,我们可以丢弃 95%的数据,但仍然可以获得 95%以上的准确性(这相当于 ROC 下的面积为 99.85%!)。
即使 MNIST 是一个“简单”的数据集,主要的要点对于大多数真实世界的数据集都是有效的。通常,仅使用一小部分特征就可以实现高水平的准确性。有效的功能选择允许您构建在内存、时间、准确性、可解释性和调试简易性方面更高效的数据管道。
感谢您的阅读!我希望这篇文章对你有用。
本文中显示的结果完全可以通过这段代码重现:https://github . com/smazzanti/mrmr/blob/main/notebooks/mnist . ipynb。
我感谢反馈和建设性的批评。如果你想谈论这篇文章或其他相关话题,可以发短信到我的 Linkedin 联系人给我。
基于 Lasso 回归的机器学习特征选择
监督特征选择的例子
查尔斯·德鲁维奥在 Unsplash 上拍摄的照片
作为一名数据科学家,我学到的第一件事是,特征选择是机器学习管道中最重要的步骤之一。幸运的是,一些模型可以帮助我们完成这个目标,给我们他们自己对特性重要性的解释。其中一个模型是套索回归。
什么是套索回归?
我已经在之前的博客文章中谈到了 Lasso 回归。让我总结一下这种模型的主要特性。这是一个使用成本函数的线性模型:
aj 是第 j 个特征的系数。最后一项称为 l1 罚项,而 α 是一个超参数,用于调整该罚项的强度。特征的系数越高,成本函数的值越高。因此,套索回归的思想是优化成本函数,减少系数的绝对值。显然,如果这些特征之前已经被缩放,例如使用标准化或其他缩放技术,这是可行的。 α 必须使用交叉验证方法找到超参数值。
我们如何使用它进行特征选择?
Lasso 回归会尝试最小化成本函数,自动选择有用的要素,丢弃无用或多余的要素。在 Lasso 回归中,丢弃一个要素将使其系数等于 0。
因此,使用 Lasso 回归进行要素选择的想法非常简单:我们在数据集的缩放版本上拟合 Lasso 回归,并且我们只考虑那些系数不为 0 的要素。显然,我们首先需要调整 α 超参数,以便获得正确的套索回归。
这很简单,会让我们很容易发现有用的特征,并丢弃无用的特征。
我们来看看用 Python 怎么做。
Python 中的示例
在本例中,我将向您展示如何使用糖尿病数据集在 Python 中使用 Lasso 进行要素选择。你可以在我的 GitHub 库中找到全部代码。
首先,让我们导入一些库:
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.linear_model import Lasso
然后,我们可以导入数据集和要素的名称。
from sklearn.datasets import load_diabetes
X,y = load_diabetes(return_X_y=True)features = load_diabetes()['feature_names']
像往常一样,我们现在可以将数据集分成训练集和测试集,并只对训练集执行所有计算。
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
现在我们必须建立我们的模型,优化它的超参数,并在训练数据集上训练它。
因为我们的数据集需要预先进行缩放,所以我们可以利用 scikit-learn 中强大的 Pipeline 对象。我们的管道是由一个标准缩放器和套索对象本身组成的。
pipeline = Pipeline([
('scaler',StandardScaler()),
('model',Lasso())
])
现在我们要优化 Lasso 回归的 α 超参数。对于本例,我们将测试 0.1 到 10 之间的几个值,步长为 0.1。对于每个值,我们在 5 重交叉验证中计算均方误差的平均值,并选择使这种平均性能指标最小化的 α 的值。为此,我们可以使用 GridSearchCV 对象。
search = GridSearchCV(pipeline,
{'model__alpha':np.arange(0.1,10,0.1)},
cv = 5, scoring="neg_mean_squared_error",verbose=3
)
我们使用 neg_mean_squared_error ,因为网格搜索试图最大化性能指标,所以我们添加一个负号来最小化均方误差。
我们现在可以进行网格搜索了。
search.fit(X_train,y_train)
α 的最佳值为:
search.best_params_# {'model__alpha': 1.2000000000000002}
现在,我们必须得到套索回归系数的值。
coefficients = search.best_estimator_.named_steps['model'].coef_
一个特性的重要性是其系数的绝对值,所以:
importance = np.abs(coefficients)
让我们看看它的重要性:
正如我们所见,有 3 个特征的重要性为 0。这些特征已经被我们的模型丢弃了。
在套索回归中幸存下来的特征是:
np.array(features)[importance > 0]# array(['age', 'sex', 'bmi', 'bp', 's1', 's3', 's5'], dtype='<U3')
而 3 个被丢弃的特征是:
np.array(features)[importance == 0]# array(['s2', 's4', 's6'], dtype='<U3')
通过这种方式,我们根据给定的目标变量,使用适当优化的 Lasso 回归来获取数据集最重要特征的信息。
结论
Lasso 回归具有非常强大的内置要素选择功能,可用于多种情况。然而,它也有一些缺点。例如,如果特征和目标变量之间的关系不是线性的,那么使用线性模型可能不是一个好主意。通常,适当的探索性数据分析可以帮助我们更好地理解特征和目标之间最重要的关系,使我们选择最佳模型。
如果你想了解更多关于 Lasso 回归的知识,加入我的 Python 在线课程监督机器学习。
原载于 2021 年 5 月 5 日 https://www.yourdatateacher.comhttps://www.yourdatateacher.com/2021/05/05/feature-selection-in-machine-learning-using-lasso-regression/。
Scikit-learn 中的功能选择
由马特·保罗·卡塔拉诺在 Unsplash 上拍摄
Python 中的机器学习
过滤特征的简单方法,以获得更简单、更快速的模型
当建立监督机器学习模型时,我们收集对预测结果潜在有用的特征。并不是所有的特性都有助于构建模型。过滤掉不可预测的特征并保持模型的精简性通常是可行的,这样模型更快,更容易向利益相关者解释,并且更容易生产。在本帖中,我们将学习一些简单的方法来剔除对预测结果没有帮助的特征,并选择贡献更大的特征。
📦 1.数据
让我们首先加载必要的库,导入一个样本玩具数据,并将其划分为训练和测试数据集:
import pandas as pd
pd.options.display.max_rows = 20
# Used Scikit-learn version 1.0.1
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.feature_selection import (RFE, SelectKBest,
SelectPercentile)
from sklearn.metrics import roc_auc_score# Load data
cancer = load_breast_cancer(as_frame=True)
X = cancer['data']
print(f"Features shape: {X.shape}")
y = cancer['target']
print(f"Target shape: {y.shape}\n")# Partition data
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
print(f"Training data - Features shape: {X_train.shape}")
print(f"Training data - Target shape: {y_train.shape}\n")
print(f"Test data - Features shape: {X_test.shape}")
print(f"Test data - Target shape: {y_test.shape}")
我们将使用有 30 个特征的乳腺癌数据。
💻 2.基线模型
我们将使用 ROC AUC(从这里开始的 AUC)来评估模型。让我们通过使用所有特性构建一个简单的模型来了解基准性能:
model0 = GradientBoostingClassifier(random_state=42)
model0.fit(X_train, y_train)def get_roc_auc(model, X, y):
y_proba = model.predict_proba(X)[:,1]
return roc_auc_score(y, y_proba)print(f"Training data - ROC AUC: {get_roc_auc(model0, X_train, y_train):.4f}")
print(f"Test data - ROC AUC: {get_roc_auc(model0, X_test, y_test):.4f}")
测试数据集的 AUC 为 0.9951。
📍 3.特征选择
我们将着眼于五种不同的方法来为有监督的机器学习问题进行特征选择。
📍 3.1.从要素重要性中过滤
要素重要性显示了每个要素对预测的贡献程度。进行特征选择的一个简单方法是删除对模型贡献不大的特征。
imp = pd.DataFrame(model0.feature_importances_, index=X.columns,
columns=['importance'])\
.sort_values('importance', ascending=False)
imp
通过使用阈值 0.01,我们可以选择重要性超过阈值的特征,如下所示。或者,如果我们在寻找前 n 个特性,我们可以像这样调整语法:imp[‘importance’].head(n).index
。
imp_features = imp[imp['importance']>0.01].index
print(f"===== {len(imp_features)} features were selected =====")
print(f"{', '.join(imp_features)}")
10 个特征高于阈值。如果我们使用这 10 个特征,让我们检查模型的性能:
model1 = GradientBoostingClassifier(random_state=42)
model1.fit(X_train[imp_features], y_train)print(f"Training data - ROC AUC: {get_roc_auc(model1, X_train[imp_features], y_train):.4f}")
print(f"Test data - ROC AUC: {get_roc_auc(model1, X_test[imp_features], y_test):.4f}")
即使我们只使用了三分之一的功能,模型性能也没有显著下降。
📍3.2.使用递归特征消除
在递归特征消除中,我们从所有特征开始,然后每次递归地丢弃最不重要的特征(step=1
),直到满足一个标准。我们将使用一个标准来保留 10 个特征。
rfe = RFE(GradientBoostingClassifier(random_state=42),
n_features_to_select=10)
rfe.fit(X_train, y_train)rfe_features = X_train.columns[rfe.support_]
print(f"===== {len(rfe_features)} features were selected =====")
print(f"{', '.join(rfe_features)}")
让我们使用选定的功能运行模型,并检查其性能:
model2 = GradientBoostingClassifier(random_state=42)
model2.fit(X_train[rfe_features], y_train)print(f"Training data - ROC AUC: {get_roc_auc(model2, X_train[rfe_features], y_train):.4f}")
print(f"Test data - ROC AUC: {get_roc_auc(model2, X_test[rfe_features], y_test):.4f}")
性能和以前一模一样。让我们看看这种方法是否选择了与以前相同的功能:
imp_features.sort_values().equals(rfe_features.sort_values())
是的,它做到了!这并不奇怪,因为两者都是基于梯度推进分类器的特征重要性。这种方法也适用于提供特征重要性或系数的其他算法。使用系数时,请记住要素的比例会影响系数。
这种方法比前一种方法慢,因为它需要多次运行模型。加快速度的一个方法是增加step
的大小,这样它可以更快地消除特征。
📍 3.用 SelectKBest 选择前 n 名
与前两种方法不同,这种方法和接下来的方法是模型不可知的。我们将根据分数选择 10 个最佳功能。 F 值被用作分类的默认分数,然而,可以使用不同的分数。
kbest = SelectKBest(k=10)
kbest.fit(X_train, y_train)# See selected features
kbest_features = X_train.columns[kbest.get_support()]
print(f"===== {len(kbest_features)} features were selected =====")
print(f"{', '.join(kbest_features)}")
现在,该用新选择的特性再次运行模型了:
model3 = GradientBoostingClassifier(random_state=42)
model3.fit(X_train[kbest_features], y_train)print(f"Training data - ROC AUC: {get_roc_auc(model3, X_train[kbest_features], y_train):.4f}")
print(f"Test data - ROC AUC: {get_roc_auc(model3, X_test[kbest_features], y_test):.4f}")
模型性能与以前的方法相似。让我们来看看选择了哪些之前没有选择的功能:
[var for var in kbest_features if var not in rfe_features]
📍 4.使用 SelectPercentile 选择前 p 个百分点
这是前一种方法的变体,它允许指定要选择的功能的百分比,而不是功能的数量。我们将选择前 33%的功能来获得前 10 个功能:
percentile = SelectPercentile(percentile=33)
percentile.fit(X_train, y_train)# See selected features
percentile_features = X_train.columns[percentile.get_support()]
print(f"===== {len(percentile_features)} features were selected =====")
print(f"{', '.join(percentile_features)}")
现在,让我们检查模型性能:
model4 = GradientBoostingClassifier(random_state=42)
model4.fit(X_train[percentile_features], y_train)print(f"Training data - ROC AUC: {get_roc_auc(model4, X_train[percentile_features], y_train):.4f}")
print(f"Test data - ROC AUC: {get_roc_auc(model4, X_test[percentile_features], y_test):.4f}")
性能和以前一样。让我们看看功能是否与前面的方法相同:
percentile_features.sort_values().equals(kbest_features.sort_values())
这是有意义的,因为我们选择了百分点值来获得与以前相同数量的特征。
📍 5.结合多种方法
如果你不想只使用一种方法,我们可以基于多种方法的组合来进行特征选择。我们来看看所有方法的总结:
selection = pd.DataFrame(index=X.columns)
selection['imp'] = [var in imp_features for var in X.columns]
selection['rfe'] = rfe.support_
selection['kbest'] = kbest.get_support()
selection['percentile'] = percentile.get_support()
selection['sum'] = selection.sum(axis=1)
selection.sort_values('sum', ascending=False, inplace=True)
selection
让我们检查一下sum
列的分布:
pd.concat([selection['sum'].value_counts(normalize=True),
selection['sum'].value_counts()], axis=1,
keys=['prop', 'count'])
该表告诉我们,16 个特征没有被任何方法选择,6 个特征被所有方法选择。由于imp_features
和rfe_features
是相同的,并且kbest_features
和percentile_features
包含相同的特征,所以看到我们在这里只看到偶数值:0,2,4 也就不足为奇了。这意味着我们实际上是在聚合两种方法。
如果我们想更加小心,我们可以删除在两种方法中都没有选择的特性:
selected_features = selection[selection['sum']>0].index
print(f"===== {len(selected_features)} features were selected =====")
print(f"{', '.join(selected_features)}")
我们现在已经选择了 14 个特征,是时候检查模型性能了:
model5 = GradientBoostingClassifier(random_state=42)
model5.fit(X_train[selected_features], y_train)print(f"Training data - ROC AUC: {get_roc_auc(model5, X_train[selected_features], y_train):.4f}")
print(f"Test data - ROC AUC: {get_roc_auc(model5, X_test[selected_features], y_test):.4f}")
该性能与具有所有功能的基线模型相同,但我们仅使用了大约一半的功能。
瞧,这就是进行特征选择的 5 种简单方法。通过有效的特征选择,我们可以在不丧失预测能力的情况下建立更简单、更快速、更易于解释的模型。希望你能在下一个有监督的机器学习任务中使用这些方法。
马克·哈普尔在 Unsplash 上拍摄的照片
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果你使用 我的推荐链接成为会员,你的一部分会费会直接去支持我。
感谢您阅读这篇文章。如果你感兴趣,这里有我的一些其他帖子的链接:
◼️ 解释 scikit-learn models with shap
◼️️k 近邻解释
◼️️ 逻辑回归解释
◼️️ 比较随机森林和梯度推进
◼️️ 决策树是如何构建的?
◼️️ 管道,ColumnTransformer 和 FeatureUnion 说明t30】◼️️feature union,ColumnTransformer &管道用于预处理文本数据
使用逻辑回归模型的特征选择
使用正则化移除冗余要素
图片来自皮克斯拜
特征工程是数据科学模型开发管道的重要组成部分。‘更多的数据导致更好的机器学习模型’,对实例的数量成立,但对特征的数量不成立。
数据科学家将大部分工作时间用于准备相关特征,以训练一个健壮的机器学习模型。原始数据集包含大量可能影响模型性能的冗余要素。特征选择是一个特征工程组件,它涉及删除不相关的特征,并挑选最佳的特征集来训练健壮的机器学习模型。
特征选择方法降低了数据的维数,避免了维数灾难的问题。在我以前的一篇文章中,我已经广泛地讨论了 7 特性选择技术:
在本文中,我们将讨论如何使用带有 L1 正则化的逻辑回归模型来移除数据中的冗余特征。
想法:
正则化是一种通过向误差函数添加惩罚来调整模型的技术。正则化可以用于训练模型,这些模型可以更好地概括测试数据或看不见的数据,并防止算法过度拟合训练数据集。
L2 正则化指的是等价于系数大小的平方的惩罚,而 L1 正则化引入了等价于系数绝对值之和的惩罚(收缩量)。
(图片由作者提供),L1 和 L2 正则项
L1 正则化在数据集中引入了稀疏性,它可以通过消除不重要的特征来执行特征选择。Lasso 或 L1 正则化将冗余特征的系数缩小到 0,因此这些特征可以从训练样本中移除。
实施:
从 Kaggle 下载的信用卡欺诈检测数据集用于演示使用 Lasso 回归模型的特征选择实现
-
读取数据集并执行要素工程(标准化)以使其适合训练逻辑回归模型。
-
在标准化的训练样本上训练最适合的逻辑回归模型。
-
使用
**model.coef_**
函数计算逻辑回归模型的系数,该函数返回逻辑回归划分平面的权重向量。
(图片由作者提供),逻辑回归模型的系数值
系数向量的维数与训练数据集中的特征数量相同。
- 等于 0 的系数值是冗余特征,可以从训练样本中去除。从上面的系数向量快照可以看出,我们有系数为 0 的 7 特征。
**coef = model.coef_[0]
imp_features = pd.Series(X_std.columns)[list(coef!=0)]****X_train = X_train[imp_features]
X_test = X_test[imp_features]**
(图片由作者提供),从信用卡数据集中删除的 7 个冗余特征的列表
在特征选择实现之前,训练样本具有 29 个特征,在去除 7 个冗余特征之后,训练样本减少到 22 个特征。
注意:
逻辑回归模型的参数‘C’
影响系数项。当正则化变得越来越松散或者‘C’
的值减小时,我们得到更多的系数值为 0。必须记住保持 ‘C’
的正确值,以获得所需数量的冗余特征。
较高的“C”值可能认为重要的特征是多余的,而较低的“C”值可能不排除多余的特征。
(来源),C 与非零系数项的关系图
结论:
套索回归(带 L1 正则化的逻辑回归)可用于移除数据集中的冗余要素。L1 正则化在数据集中引入了稀疏性,并将冗余特征的系数的值缩小到 0。
通过移除不相关的特征来降低数据集的维度是一种非常有用的技术或技巧。
还有各种其他的特征选择技术。我在以前的一篇文章中已经讨论过 7 这样的特征选择技术:
参考资料:
[1] Scikit-learn 文档:https://sci kit-learn . org/stable/auto _ examples/linear _ model/plot _ logistic _ path . html
感谢您的阅读
专题选择:科学与艺术相遇的地方
戴维·克洛德在 Unsplash 上的照片
从启发式到算法的数据科学项目特征选择技术
有人说特征选择和工程是数据科学项目中最重要的部分。在许多情况下,并不是复杂的算法,而是特征选择决定了模型性能的差异。
太少的特征会使模型不适合。例如,如果你想预测房价,仅仅知道卧室的数量和建筑面积是不够的。你忽略了许多买家关心的重要变量,如位置、学区、房龄等。
你也可以从另一个方向来,选择 100 个不同的特征来描述每一个微小的细节,如财产上的树木名称。这些特性没有增加更多的信息,反而增加了噪音和复杂性。许多选择的功能可能完全不相关。最重要的是,太多的特征增加了训练模型的计算成本。
因此,要建立一个好的预测模型,特征的正确数量是多少,以及如何选择保留哪些特征、删除哪些特征以及添加哪些新特征?这是机器学习项目中管理所谓的偏差-方差权衡的一个重要考虑因素。
这也是“科学”与“艺术”相遇的地方
本文的目的是通过一些简单的实现来揭开特性选择技术的神秘面纱。我下面描述的技术应该同样适用于回归和分类问题。无监督分类(例如聚类)可能有点棘手,所以我将单独讨论它。
启发式方法
我们不太谈论数据科学中的试探法,但它非常相关。我们来看看定义(来源:维基百科):
启发式或启发式技术 …采用一种实用的方法,这种方法不能保证是最佳的、完美的或合理的,但足以达到一个直接的、短期的目标或近似值。
如果是基于直觉,这个定义同样适用于特征选择。仅仅通过查看一个数据集,你就会直觉地感觉到这样那样的特征是强有力的预测器,而其他一些特征与因变量无关,你会觉得消除它们是安全的。
如果不确定,可以进一步检查特征和因变量之间的相关性。
在数据集中有太多要素的情况下,仅这些启发式方法(直觉和相关性)就可以完成选择正确要素的大部分工作。
举个例子,假设你的公司正在分配不同渠道(电视、广播、报纸)的广告预算。你想预测哪个渠道作为广告平台最有效,预期回报是多少。
在建立模型之前,您查看历史数据,发现不同平台上的广告费用与相应的销售收入之间存在以下关系。
显示不同平台上销售额和广告支出之间关系的二元散点图(图来源:作者;数据来源: ISLR ,许可证:GLP 2,公共领域)。
根据散点图,你认为解释广告收入的最佳特征是什么?显然,报纸广告对结果没有任何重大影响,所以你可能想把它从模型中去掉。
自动特征选择
我们现在将进入自动特征选择技术。它们中的大部分都集成在sklearn
模块中,所以您只需用标准格式的几行代码就可以实现特性选择。
为了演示,我将使用‘iris’数据集(来源: Kaggle/UCI 机器学习,许可证:CC0 公共域)。这是一个简单的数据集,只有 5 列,然而,你会得到关键点。
让我们从seaborn
库中加载数据集。
# import seaborn library
**import seaborn as sns**# load iris dataset
**iris = sns.load_dataset('iris')
iris.head(5)**
# separate features (X) from the target (y) variable
**X = iris.drop('species', axis=1)
y = iris['species']**
在数据集中,“物种”是我们想要预测的,其余 4 列是预测值。让我们以编程方式确认特性的数量:
# number of predictors in the current dataset
**X.shape[1]**>> 4
现在让我们来实现一些特性选择技术。
1)基于卡方的技术
基于卡方的技术基于一些分数选择特定数量的用户定义的特征(k)。这些分数是通过计算 X(自变量)和 y(因变量)之间的卡方统计来确定的。
sklearn
内置了基于卡方的特征选择方法。您所要做的就是确定想要保留多少个特征(假设虹膜数据集的 k=3)。
# import modules **from sklearn.feature_selection import SelectKBest, chi2**# select K best features
**X_best = SelectKBest(chi2, k=3).fit_transform(X,y)**
现在让我们确认一下,我们已经获得了 4 个特性中的 3 个最佳特性。
# number of best features
**X_best.shape[1]**>> 3
对于大量的特性,您可以指定要保留或删除的特性的某个百分比。它的工作方式与上面类似。假设我们想保留 75%的特性,去掉剩下的 25%。
# keep 75% top features
**X_top = SelectPercentile(chi2, percentile = 75).fit_transform(X,y)**# number of best features
**X_top.shape[1]**>> 3
2)基于杂质的特征选择
基于树的算法(如随机森林分类器)具有内置的feature_importances_
属性。
决策树将使用减少杂质的特征来分割数据(根据基尼杂质或信息增益来测量)。这意味着,找到最佳特征是算法如何解决分类问题的关键部分。然后,我们可以通过feature_importances_
属性访问最佳特性。
让我们首先将“iris”数据集与具有 200 个评估者的随机森林分类器相匹配。
# import model
**from sklearn.ensemble import RandomForestClassifier**# instantiate model
**model = RandomForestClassifier(n_estimators=200, random_state=0)**# fit model
**model.fit(X,y)**
现在让我们通过属性调用来访问特性重要性。
# importance of features in the model
**importances = model.feature_importances_****print(importances)**>> array([0.0975945 , 0.02960937, 0.43589795, 0.43689817])
上面的输出显示了 4 个特征中的每一个在减少每个节点/分裂处的杂质方面的重要性。
由于随机森林分类器有许多估计器(例如,上面的 200 个决策树),我们可以用置信区间计算相对重要性的估计。让我们想象一下。
# calculate standard deviation of feature importances
**std = np.std([i.feature_importances_ for i in model.estimators_], axis=0)**# visualization**feat_with_importance = pd.Series(importances, X.columns)****fig, ax = plt.subplots()
feat_with_importance.plot.bar(yerr=std, ax=ax)
ax.set_title("Feature importances")
ax.set_ylabel("Mean decrease in impurity")
fig.tight_layout()**
图:杂质测量中特征的重要性(来源:作者)
既然我们知道了每个特性的重要性,我们就可以手动(或直观地)决定保留哪些特性,放弃哪些特性。
或者,我们可以利用 Scikit-Learn 的元转换器SelectFromModel
来完成这项工作。
# import the transformer
**from sklearn.feature_selection import SelectFromModel**# instantiate and select features
**selector = SelectFromModel(estimator = model, prefit=True)
X_new = selector.transform(X)
X_new.shape[1]**>> 2
3)正规化
正则化是机器学习中减少过拟合的一个重要概念(阅读:用正则化避免过拟合)。如果有太多的要素,正则化通过收缩要素系数(称为 L2 正则化/岭回归)或通过将一些要素系数设置为零(称为 L1 正则化/LASSO 回归)来控制其效果。
一些线性模型内置 L1 正则化作为超参数来惩罚特征。这些特征可以用元转换器SelectFromModel
消除。
让我们用超参数惩罚=‘L1’来实现LinearSVC
算法。然后,我们将使用SelectFromModel
删除一些功能。
# implement algorithm
**from sklearn.svm import LinearSVC
model = LinearSVC(penalty= 'l1', C = 0.002, dual=False)
model.fit(X,y)**# select features using the meta transformer
**selector = SelectFromModel(estimator = model, prefit=True)
X_new = selector.transform(X)
X_new.shape[1]**>> 2# names of selected features
**feature_names = np.array(X.columns)
feature_names[selector.get_support()]**>> array(['sepal_length', 'petal_length'], dtype=object)
4)顺序选择
顺序特征选择是一种古老的统计技术。在这种情况下,您将逐个向模型添加(或从中移除)特征,并检查模型性能,然后试探性地选择要保留的特征。
顺序选择有两种变体。前向选择技术从零个特征开始,然后增加一个最大程度地减小误差的特征;然后添加另一个特征,等等。反向选择反方向工作。该模型从所有特征开始并计算误差;然后,它消除一个特征,使误差进一步最小化,以此类推,直到剩下所需数量的特征。
Scikit-Learn 模块有SequentialFeatureSelector
元转换器,让生活更轻松。注意,它适用于sklearn
v0.24 或更高版本。
# import transformer class
**from sklearn.feature_selection import SequentialFeatureSelector**# instantiate model
**model = RandomForestClassifier(n_estimators=200, random_state=0)**# select features
**selector = SequentialFeatureSelector(estimator=model, n_features_to_select=3, direction='backward')
selector.fit_transform(X,y).shape[1]**>> 3# names of features selected
**feature_names = np.array(X.columns)
feature_names[selector.get_support()]**>> array(['sepal_width', 'petal_length', 'petal_width'], dtype=object)
替代技术……
除了我刚刚描述的技术,还有一些其他的方法可以尝试。它们中的一些并不完全是为特征选择而设计的,但是如果你深入一点,你会发现它们是如何创造性地应用于特征选择的。
- Beta 系数:运行线性回归后得到的系数(Beta 系数)显示了因变量对每个特征的相对敏感度。从这里您可以选择具有高系数值的特征。
- p 值:如果你在一个经典的统计软件包(如
statsmodels
)中实现回归,你会注意到模型输出包括每个特征的 p 值(看看这个)。p 值检验系数正好为零的零假设。因此,您可以消除与高 p 值相关的特征。 - 方差膨胀因子(VIF) :通常 VIF 用于检测数据集中的多重共线性。统计学家通常移除具有高 VIF 的变量,以满足线性回归的关键假设。
- 【AIC/BIC】:通常用 AIC 和 BIC 来比较两个模型的性能。但是,您可以利用它来进行特征选择,例如,通过选择某些特征来获得以 AIC/BIC 衡量的更好的模型质量。
- 主成分分析(PCA) :如果你知道什么是 PCA,你就猜对了。这不完全是一种特征选择技术,但是 PCA 的降维特性可以用于这种效果,而不完全消除特征。
- 和许多其他的:有很多其他的特性选择类和
sklearn
模块一起提供,查看文档。最近在一篇科学论文中也提出了一种基于聚类的算法。费希尔评分是另一种可用的技术。
集群怎么样?
聚类是一种无监督的机器学习算法,这意味着你将数据输入到聚类算法中,该算法将根据一些“属性”计算出如何将数据分成不同的聚类。这些属性实际上来自于特性。
聚类需要特征选择吗?当然了。没有适当的特征,集群可能是无用的。假设您想要细分客户,以便销售高端、中档和低端产品。这意味着你含蓄地使用客户收入作为一个因素。你也可以通过教育进入混。他们的年龄和经验年限?当然可以。但是,当您增加功能的数量时,算法会对您想要实现的目标感到困惑,因此输出可能并不完全是您想要的。
也就是说,数据科学家并不是在真空中运行聚类算法,他们头脑中通常有一个假设或问题。因此,功能必须符合这种需求。
摘要
数据科学家非常重视特征选择,因为它对模型性能有影响。对于低维数据集,试探法和直觉完美地工作,然而,对于高维数据,有自动化技术来完成这项工作。最有用的技术包括卡方和基于杂质的算法以及正则化和顺序特征选择。此外,还有其他有用的替代技术,如回归中的β系数、p 值、VIF、AIC/BIC 和维度缩减。
在这篇文章的标题里,我说的是“科学遇见艺术”。这是因为在功能选择上没有对错之分。我们可以使用科学工具,但最终,这可能是数据科学家做出的主观决定。
感谢阅读。请随意订阅以获得我即将发布的文章的通知,或者通过 Twitter 或 LinkedIn 与我联系。
Python 中 Boruta 的特征选择
了解 Boruta 算法如何用于特征选择。说明+模板
特征选择过程是任何机器学习项目的基础。在本文中,我们将介绍 Boruta 算法,该算法允许我们对我们的特性、进行排序,从最重要到对我们的模型影响最小。Boruta 使用简单,是一种强大的技术,分析师应该将它纳入到他们的管道中。
介绍
Boruta 不是一个独立的算法:它位于随机森林算法之上。事实上,这个名字 Boruta 来源于斯拉夫神话中森林之魂的名字。为了理解算法是如何工作的,我们将对随机森林做一个简单的介绍。
随机森林是基于装袋的概念——即从训练集中创建许多随机样本,并为每个样本训练不同的统计模型。对于分类任务,结果是来自模型的大多数投票,而对于回归任务,结果是各种模型的平均值。
规范装袋与随机森林的区别在于后者总是只使用决策树模型。对于所考虑的每个样本,决策树考虑了一组有限的特征。这使得随机森林算法能够估计每个特征的重要性,因为它基于所考虑的特征分割将误差存储在预测中。
让我们考虑一个分类任务。RF 估计特征重要性的方法分两个阶段进行。首先,每个决策树创建并存储一个预测。其次,通过各种训练样本随机排列某些特征的值,并重复上一步,再次追踪预测的结果。单个决策树的特征的重要性被计算为使用原始特征的模型与使用置换特征的模型之间的性能差异除以训练集中的示例数量。特征的重要性是该特征在所有树上的测量值的平均值。在此过程中没有做的是计算每个特征的 z 分数。这就是博鲁塔发挥作用的地方。
Boruta 如何工作
Boruta 的想法既有趣又简单:对于原始数据集中的所有特征,我们将创建它们的随机副本(称为阴影特征),并基于这个扩展的数据集训练分类器。为了理解一个特征的重要性,我们将它与所有生成的阴影特征进行比较。只有在统计上比这些合成特征更重要的特征才会被保留,因为它们对模型性能的贡献更大。让我们更详细地看看这些步骤。
- 创建训练集特征的副本,并将它们与原始特征合并
- 在这些合成特征上创建随机排列,以消除它们与目标变量 y 之间的任何相关性——基本上,这些合成特征是它们所源自的原始特征的随机组合
- 合成特征在每次新的迭代中被随机化
- 在每次新的迭代中,计算所有原始和合成特征的 z 值。如果某个特征的重要性高于所有合成特征的最大重要性,则认为该特征是相关的
- 对所有原始特征应用统计测试并保存其结果。无效假设是一个特征的重要性等于合成特征的最大重要性。统计测试测试原始特征和合成特征之间的相等性。当一个特征的重要性明显高于或低于一个综合特征的重要性时,零假设被拒绝
- 从原始和合成数据集中移除被认为不重要的特征
- 重复所有步骤,重复 n 次,直到所有特征都被移除或被认为重要
应该注意的是,Boruta 是一种启发式算法:它的性能没有保证。因此,建议多次运行该过程,并反复评估结果。
Boruta 在 Python 中的实现
让我们看看 Boruta 如何在 Python 中使用它的专用库工作。我们将使用 Sklearn.datasets 的 load_diabetes() 数据集在一个回归问题上测试 Boruta。
特征集 X 由变量组成
- 年龄(年)
- 性
- 身体质量指数
- 平均血压
- s1(总胆固醇)
- s2(低密度脂蛋白)
- s3(高密度脂蛋白,高密度脂蛋白)
- s4(总胆固醇/高密度脂蛋白胆固醇)
- s5 (ltg,甘油三酯水平的对数)
- s6 (glu,血糖水平)
目标 y 是记录的糖尿病随时间的进展。
通过运行这个脚本,我们将在终端中看到 Boruta 是如何构建推理的
Boruta 在 Sklearn 糖尿病数据集上 10 次迭代的结果。图片作者。
这份报告可读性也很强
Boruta 结果报告——简单易懂的特征选择。图片作者。
根据 Boruta 的说法, bmi、bp、s5 和 s6 是对构建我们的预测模型贡献最大的特征。为了过滤我们的数据集并只选择对 Boruta 重要的特性,我们使用了feat _ selector . transform(NP . array(X)),它将返回一个 Numpy 数组。
由 Boruta 选择的特性。拟合 _ 变换。这个向量就可以用于训练了。图片作者。
我们现在准备好为我们的 RandomForestRegressor 模型提供一组选定的 X 特性。我们训练模型并打印均方根误差(RMSE)。
这是训练结果
RandomForestRegressor 模型对所选值的要素集的预测和误差。图片作者。
结论
Boruta 是一个强大而简单的特征选择算法,在网上得到广泛使用和赞赏,尤其是在 Kaggle 上。它的有效性和解释的简易性为数据科学家的工具包增加了价值,因为它是从著名的决策/随机森林算法扩展而来的。
尝试一下,享受一个更高性能的模型,它接收的信号比噪声多一点;)
推荐阅读
对于感兴趣的人来说,这里有一个我为每个与 ML 相关的主题推荐的书籍列表。在我看来,有一些必不可少的书籍对我的职业生涯产生了巨大影响。
免责声明:这些是亚马逊会员链接。我会收到亚马逊为你推荐这些项目的一小笔佣金。你的体验不会改变,你也不会被收取更多费用,但它将帮助我扩大业务规模,围绕人工智能制作更多内容。
- ML 简介 : 自信的数据技能:掌握数据工作的基本原理,为你的职业生涯增压 作者:基里尔·叶列缅科
- sk Learn/tensor flow:使用 Scikit-Learn、Keras 和 TensorFlow 进行动手机器学习,作者 Aurelien Géron
- NLP : 文本即数据:机器学习和社会科学的新框架 作者贾斯汀·格里默
- sk Learn/PyTorch:用 py torch 和 Scikit 进行机器学习——Learn:用 Python 开发机器学习和深度学习模型Sebastian Raschka
- Cole Knaflic 著 Data 即 : 用数据讲故事:商务人士数据可视化指南
有用的链接(我写的)
- 了解如何在 Python 中执行顶层探索性数据分析:Python 中的探索性数据分析——一步一步的过程
- 学习 TensorFlow 的基础知识:tensor flow 2.0 入门—深度学习入门
- 用 Python 中的 TF-IDF 进行文本聚类 : 用 Python 中的 TF-IDF 进行文本聚类
如果你想支持我的内容创作活动,欢迎点击我下面的推荐链接,加入 Medium 的会员计划。我将收到你投资的一部分,你将能够以无缝的方式访问 Medium 的大量数据科学文章。
https://medium.com/@theDrewDag/membership
代码模板
这是本文中展示的整个代码的复制粘贴版本。
基于遗传算法的特征选择
确定最佳特征集的自然选择过程。
尤金·日夫奇克在 Unsplash 上拍摄的照片
遗传算法是一种基于自然选择的优化问题的技术。在这篇文章中,我将展示如何使用遗传算法进行特征选择。
虽然在 scikit-learn 中有许多众所周知的特性选择方法,但特性选择远远超出了那里可用的范围。
特征选择是任何机器学习管道的关键方面。然而,这些天有过剩的可用数据。因此,通常会有过多的功能。
正如许多特性经常出现的情况一样,许多特性是多余的。它们给你的模型增加了噪声,并使模型解释成问题。
问题是确定什么特性与问题相关。目的是要有质量特征。
遗传算法
这篇文章使用了' sklearn-genetic' 包:
https://github.com/manuel-calzolari/sklearn-genetic
该软件包与现有的 sklearn 模型兼容,并为基因选择提供了大量的功能和选项。
在这篇文章中,我使用遗传算法进行特征选择。但是,遗传算法也可以用于超参数优化。因为这些步骤非常简单和通用,它适用于许多不同的领域。
遗传算法(图片由作者提供)
特征选择
特征选择是一个 NP 难问题。给定一组功能,最佳配置是这些功能的集合或子集。这种方法是一种离散选择。由于各种可能性,确定最佳特征集的成本非常高。
遗传算法使用一种基于进化的方法来确定最优集合。对于特征选择,第一步是基于可能特征的子集生成群体。
从这个群体中,使用目标任务的预测模型来评估子集。一旦群体中的每个成员都被考虑,就会进行一场比赛来确定哪些子集将延续到下一代。下一代由锦标赛获胜者组成,具有一些交叉(用来自其他获胜者的特征更新获胜特征集)和突变(随机引入或移除一些特征)。
- 产生初始群体。
- 一个分数被附加到群体的成员上。
- 选择一个子集用于比赛的再现。
- 选择遗传物质来传递。
- 应用突变。
- 重复多代。
该算法运行一定数量的代(迭代)。之后,群体中的最优成员就是所选择的特征。
实验
实验基于 UCI 乳腺癌数据集,该数据集包含 569 个实例和 30 个特征。有了这个数据集,我用所有的特征、来自遗传算法的特征子集和使用卡方检验进行比较的五个特征来测试几个分类器。
下面是使用遗传算法选择最多五个特征的代码。
from sklearn.datasets import load_breast_cancer
from genetic_selection import GeneticSelectionCV
from sklearn.tree import DecisionTreeClassifier
import pandas as pd
import numpy as npdata = load_breast_cancer()
df = pd.DataFrame(data.data, columns=data.feature_names)
df['target'] = data.target
X = df.drop(['target'], axis=1)
y = df['target'].astype(float)estimator = DecisionTreeClassifier()
model = GeneticSelectionCV(
estimator, cv=5, verbose=0,
scoring="accuracy", max_features=5,
n_population=100, crossover_proba=0.5,
mutation_proba=0.2, n_generations=50,
crossover_independent_proba=0.5,
mutation_independent_proba=0.04,
tournament_size=3, n_gen_no_change=10,
caching=True, n_jobs=-1)
model = model.fit(X, y)
print('Features:', X.columns[model.support_])
遗传学选择
初始群体(大小为‘n _ population’)是从特征集的样本空间中随机生成的。这些集合的范围受到参数“max_features”的限制,该参数设置每个特征子集的最大大小。
对于初始群体的每个成员,用目标度量来测量分数。这个度量是指定的估计器的性能。
进行锦标赛选择以确定哪些成员将延续到下一代。锦标赛中的成员数量由“锦标赛大小”设置。锦标赛规模是从人群中选择一些成员,根据得分标准相互竞争。锦标赛的获胜者被选为下一代的父母。
锦标赛选择流程(图片由作者提供)
参加锦标赛的人数应该保持在很少的水平。当该值相当大时,通常选择当前最佳成员。这种行为不会导致较弱的成员被选中。虽然提供了暂时的性能增益,但最终会导致整体性能下降,因为较弱的选项没有机会改进。
自然选择
在自然选择中,遗传信息储存在染色体中。在生殖过程中,一些遗传物质从父母传给子女。那么这个孩子就包含了父母双方的遗传物质。该属性用参数“crossover_proba”表示。指定的概率表示从一个世代到下一个世代的交叉机会。还有参数‘crossover _ independent _ proba’,是一个特征交叉到子代的概率。
进化的一个重要方面是突变。变异降低了搜索陷入局部最优和停滞的风险。在每一代中,除了交叉之外,还会添加一个随机突变。突变发生的概率由参数‘突变 _ 概率’设定。这个参数与' mutation_independent_proba '相结合,是将一个特性添加到特性集的机会。
值得注意的是,将这个概率设置得太高会将算法转换成随机选择过程。因此,您会希望保持这个值相对较低。在每一代中随机引入特征有效地作为遗传过程的正则化。
这里使用的遗传搜索算法也有一个“n_gen_no_change”参数,用于监控种群中的最佳成员在几代中是否没有发生变化。搜索在这种情况下找到了一个最优解。考虑增加突变或交叉概率以进一步改变选择。
结果
遗传特征选择与卡方特征选择的结果如下所示。基准性能也使用所有特性列出。结果来自交叉验证,测量的性能是准确性,使用的特征数量在括号中。
特征选择性能比较(图片由作者提供)
虽然这些结果决不是结论性的,但它们显示了遗传算法的好处。模型性能基于来自遗传算法的特征子集,该特征子集一贯优于基线模型和卡方特征子集。逻辑回归模型有一个例外,其结果仍然具有可比性。
此外,产生的最佳特征子集小于五个特征的最大值。具有较少特征的模型最终比更大的模型更受青睐,因为它们更简单且更易解释。
结论
遗传算法是难以置信的多才多艺,适用于广泛的场景。
这篇文章使用 sklearn-genetic 包探讨了如何将遗传算法用于特征选择。这些算法在超参数搜索和创成式设计中也被证明是有效的。
虽然没有 sklearn 中现有的方法那么传统,但遗传算法提供了一种独特而实用的特征选择方法。这些算法优化的方式远远不同于大多数其他特征选择方法。这个过程是基于纯粹的自然选择方法。
我鼓励数据科学家在工作中花时间理解和实现遗传算法。
如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。
如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。
https://zjwarnes.medium.com/membership
随机森林特征选择
让我们看看如何使用随机森林进行特征选择
史蒂文·卡梅纳在 Unsplash 上拍摄的照片
特征选择一直是机器学习中的一大难题。根据我的经验,我可以说这是数据科学项目中最重要的一部分,因为它帮助我们降低数据集的维度,去除无用的变量。幸运的是,有一些模型可以帮助我们计算特性的重要性,这有助于我们忽略不太有用的特性。随机森林就是这样一个模型。
什么是随机森林?
随机森林是一个监督模型,实现了决策树和 bagging 方法。其思想是根据一个称为“引导”的过程对训练数据集进行重新采样。每个样本都包含原始列的一个随机子集,用于拟合决策树。模型的数量和列的数量是要优化的超参数。
最后,将树的预测混合在一起,计算平均值(用于回归)或使用软投票(用于分类)。
bagging 的思想是,通过平均单个决策树的输出,根据偏差-方差权衡,标准误差减小,模型的方差也减小。这就是为什么兰登森林在最近几年变得非常有名。
随机森林如何计算特征重要性?
随机森林的每棵树可以根据其增加叶子纯度的能力来计算特征的重要性。这是一个关于分类和回归树(CART)如何工作的话题。叶子纯度的增量越高,该特征的重要性越高。对每棵树都这样做,然后在所有树中平均,最后归一化为 1。因此,由随机森林计算的重要性分数之和是 1。
使用递归特征消除的特征选择
一旦我们知道了每个特征的重要性,我们就使用一个叫做递归特征消除的过程来执行特征选择。在本文中,我将讨论利用 k-fold 交叉验证的版本。
想法是拟合模型,然后移除不太相关的特征,并计算 CV 中某些性能指标的平均值。然后,我们删除倒数第二个重要特征,再次拟合模型,并计算平均性能。我们一直这样做,直到没有特征剩下。最大化 CV 性能的特性集是我们必须使用的特性集。请注意,整个过程需要对超参数使用相同的值。
Python 中使用随机森林的特征选择
既然理论已经很清楚了,那我们就用 sklearn 在 Python 中应用一下吧。对于本例,我将使用波士顿数据集,这是一个回归数据集。
让我们首先导入我们需要的所有对象,即我们的数据集、随机森林回归器和将使用 CV 执行 RFE 的对象。最后,matplotlib 用于可视化我们的结果。
import numpy as np from sklearn.datasets
import load_boston from sklearn.ensemble
import RandomForestRegressor from sklearn.model_selection
import train_test_split from sklearn.feature_selection
import RFECV import matplotlib.pyplot as plt
首先,让我们加载数据集。
X,y = load_boston(return_X_y=True)
features = load_boston()['feature_names']
现在我们可以把它分成训练和测试。
X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.33, random_state=42)
现在我们可以拟合我们的随机森林回归量。在实际项目中,我们必须优化超参数的值。对于这个例子,我将使用默认值。我将只设置随机状态,以使结果可重复。
rf = RandomForestRegressor(random_state=0)
rf.fit(X_train,y_train)
拟合回归变量后,特征的重要性存储在估计器实例的 feature_importances_ 属性中。
例如,让我们画一个条形图,按照从最重要到不太重要的顺序排列特性。我们必须创建一个元组列表。元组的第一个元素是特征名,第二个元素是重要性。然后,我们根据重要性值对列表进行排序,并绘制一个水平条形图。
f_i = list(zip(features,rf.feature_importances_))
f_i.sort(key = lambda x : x[1]) plt.barh([x[0] for x in f_i],[x[1] for x in f_i])
plt.show()
作者图片
正如我们所看到的,LSTAT 特性是最重要的,其次是 RM、DIS 和其他特性。水平条形图是表示特性重要性的非常有用的图表。
现在,让我们根据交叉验证的 RFE,使用特征重要性来选择最佳特征集。对于本例,我们试图优化的指标是负均方误差。我们将使用 5 个折叠进行交叉验证,这是一个非常好的值。
rfe = RFECV(rf,cv=5,scoring="neg_mean_squared_error")
rfe.fit(X_train,y_train)
整套功能包括:
所选功能包括:
selected_features = np.array(features)[rfe.get_support()]
正如我们所看到的,RFE 忽略了不太相关的特性(CHAS)。
结论
随机森林对于回归和分类都是一个非常强大的模型。它还可以给出它自己对特征重要性的解释,这可以被绘制并用于根据例如递归特征消除过程来选择信息最丰富的特征集。正确使用,特性重要性可以给我们很好的和容易理解的可交付物(条形图)和有效的优化(特性选择)。这就是为什么我认为特征重要性是每个机器学习项目的必要组成部分。
www.yourdatateacher.com上 教授机器学习和数据科学的数据科学家吉安卢卡·马拉托。
原载于 2021 年 10 月 11 日 https://www.yourdatateacher.comhttps://www.yourdatateacher.com/2021/10/11/feature-selection-with-random-forest/。
特征存储:机器学习的数据平台
最先进的开源和自主开发的功能商店,可大规模生成、管理和提供功能
特征数据(或简称为特征)对于机器学习 (ML)模型做出的准确预测至关重要。特征存储最近成为 ML 堆栈的重要组成部分,它通常支持以下任务作为 ML 工作流的一部分:
- 自动化特征计算,例如回填、UDF
- 管理功能元数据,例如沿袭、版本
- 跨不同团队共享和重用功能
- 离线、实时或按需提供或提取功能
- 监控功能从生成到服务的整个生命周期
对于“最先进的”特征商店的调查,https://www.featurestore.org/https://www.featurestore.org/整合并比较了主要的类似“特征商店”的系统。如上所述,许多科技公司由于其独特的数据架构和业务需求,已经在内部建立了自己的功能商店。例如,优步的业务是为用户提供低延迟服务。对于 Airbnb 来说,个性化推荐是让旅行者在他们的平台上预订住宿的关键。
在这样的组织中,跨不同业务单位的多个 ML 数据团队可能独立地操作相同的 ML 工作流,因此有必要整合工作并提供一个功能存储来标准化和管理功能的整个生命周期并为所有团队服务。
将上述想法反馈到 ML 社区,为一般 ML 用例建立一个标准的、开箱即用的特性库听起来很有希望,可能从小规模的简单用例开始。
下面,我将简要介绍两家科技公司的主要特色商店:优步和 Airbnb** ,以及一家开源特色商店: 盛宴 。最后分享一下我个人对通用 ML 平台的想法。**
Airbnb: Zipline
Airbnb 至少在 4 年前建立了他们的特色商店,名为 Ziplin。最近的一次演讲来自于 Spark AI 2020 ,以下是我的心得:
(Airbnb 的许多功能都是从“滑动窗口”操作中产生的。请参阅以下示例功能(过去 30 天内对一家餐厅的平均评分)。
rating_features = GroupBy(
sources=EventSource(
event_stream="restaurant_check_in_stream",
event_log_table="core_data.restaurant_check_ins",
query=Query(
select=Select(
restaurant="id_restaurant",
rating="CAST(rating as Double) - 2.5",
)
)
)
keys=["restaurant"],
aggregations=Aggregations(
avg_rating=Aggregation(
documentation="Avg rating for this restaurant",
operation=AVG,
inputColumn="rating",
**windows=[Window(length=30, timeUnit=TimeUnit.DAYS)]**
)
)
)
(2)为了有效地支持滑动窗口操作,他们提出了一个算子的性质,称为“可逆性”。
Reversible: (a + b) - a = b
有些运算符具有上述性质,例如,和,平均,【AVG】,,计数。当在滑动窗口中计算时,他们不需要为整个窗口进行计算,相反,由于“可逆性”属性,他们只是丢弃窗口之外的内容,并向窗口添加新的内容。
滑动窗口示例
有些运算符不具有“可逆性”属性,如 Min , Max 。当在滑动窗口中计算这种算子时,在滑动窗口内的数据上建立一个二叉树,这样当旧数据滑出和新数据进入时,二叉树被调整,并且它的根总是 Min 、 Max 等的答案。
图片来源:https://www.youtube.com/watch?v=LjcKCm0G_OY的滑索演示
例如,4 曾经是窗口中的最大值。当 4 滑出时,将从 1 中选择根,3,2 和 3 将是新的根。
通过利用树结构,时间复杂度从 O(N)降低到 O(NlogN ),空间复杂度从 2N 降低到 N
优步:米开朗基罗调色板
早期,优步开始建立他们的特色商店,叫做米开朗基罗调色板。最近的演讲是在这里,我的收获是:
(1) 80%的 ML 工作负荷是特征工程,例如,发现好的特征、大规模地提供特征、特征对等性(训练/服务偏斜)、实时特征、特征可观察性。
(2)以下抽象使得特征有组织、可重用、高效:
- 实体:优步的一个业务单位,如顺风车、司机、优步 Eats
- 特性组:一组常用的特性
- 特征 : ML 就绪数据点
- 连接键:用于连接用户标识、餐厅标识等功能的键。这允许在现有特征的基础上创建新特征。
(3)三大类特征
- 批量特征(通过火花):例如 sum_orders_1week,avg_order_size_30day
- 近实时特征(通过卡夫卡、弗林克):例如眼球 _ 印象 _ 5 _ 分钟
- RPC 特征(来自外部 API、第三方的信号):例如 geohash
(4)特征质量监控:特征管道断裂、特征数据缺失、漂移和不一致是常见的。已经实施了以下方法来解决这些问题:
图片来源:https://vimeo.com/477753622的优步特色工程展示
盛宴:开源特性商店
GoJek/Google 在 2019 年初发布了盛宴,它是围绕 Google 云服务而构建的:大查询(离线)和大表(在线)和 Redis (低延迟),使用 Beam 进行特征工程。
图片来源:盛宴建筑https://feast.dev/post/a-state-of-feast/
从目前的 Feast 架构来看,它的重点是特性存储、服务和注册。这里是一篇很棒的文章,介绍什么是盛宴,当前的挑战是什么,下一个是什么。
我的想法
对于通用 ML 数据平台,以下是我的 3 点个人想法:
(1)最有价值和最具挑战性的问题之一是从原始数据到高质量、ML 友好特性的数据转换。解决这个问题高度依赖于 ML 工程师的领域知识,并由业务用例驱动。换句话说,一个独立的 ML 数据平台如果不服务于特定的业务场景、用例,不与优秀的 ML 工程师团队无缝协作,那么它就是无效的。
(2)在技术方面,ML 数据平台需要支持下面的各种主流基础设施,无论它们是开源的还是商业的,是在内部运行还是在云上运行。关于平台 API,它必须支持流行的编程语言,比如 Python。出于安全考虑,it 必须提供企业级授权和身份认证,以便为北美和欧洲等监管严格的地区的客户提供服务。对于数据隐私,it 部门必须完全遵守当地政策,绝不妥协。
(3)在规模方面,随着 ML 数据平台外部产品用户和内部用户的快速增长,在业务用例和技术栈上应该高度规模化。仅举几个例子,
- 提供一个通用和灵活的接口,让 ML 工程师能够容易和准确地描述任何类型的特征
- 每天优化数千个新功能的上线
- 跨不同的领域有效且高效地应用不断变化的隐私策略
- 管理异构基础架构,将新出现的基础架构添加到设备群中,并顺利淘汰旧的基础架构。
功能商店需要一个 HTAP 数据库
图片经由 Cybrain /Adobe Stock 在 Zer0 到 5ive 的许可下
特征存储是用于训练和服务机器学习模型的组织和管理的特征的集合。使它们保持最新、服务于特征向量以及创建训练数据集需要结合事务性(OLTP)和分析性(OLAP)数据库处理。这种混合工作负载数据库被称为混合事务分析处理的 HTAP。
最有用的要素存储包含数据管道,这些管道通过与源数据节奏相匹配的批处理或实时处理来持续保持其要素最新。因为这些特征总是最新的,所以它们提供了用于推理的特征向量的理想来源。特征向量甚至可以从特征库中实时传递。完整的特征存储保存特征值的历史,并使用它来创建时间准确的训练数据集。
生产中的特征存储保持特征值最新,使 ML 模型能够快速进入生产。通常,功能是基于共同的上下文(即客户、产品、位置)和数据节奏进行分组的。为每个组提供适当节奏的数据管道使功能保持最新。有了现成的精选特征,许多推理引擎无需任何额外的努力就可以访问它们。
功能存储数据流
在上图中,我们用橙色表示低延迟/高并发处理,这通常是 OLTP 数据库的特征。我们用蓝色表示大规模并行处理数据库引擎(通常称为 OLAP)中的高容量数据处理。让我们来看看为什么我们需要两者来最大限度地运行一个特性库。
批量数据流水线定期发生(通常一天或一周一次)。它们通过提取、加载、清理、聚合和以其他方式将数据管理成可用的特征来处理大量的源数据。建立 RFM 客户档案是一个常见的例子。客户活动用于计算多个类别和多个移动时间窗口(可能包括过去 24 小时、上周、上月和去年)的近期、频率和货币指标。为大量客户和交易转换这些数据通常需要并行处理,随着业务增长导致数据量增加,这种并行处理可以扩展。
训练数据集是通过扫描和连接具有感兴趣的特征和事件历史的大型数据集而创建的。这些联接跨越多个不同的特征组,并将每个训练案例与对应于每个事件时间的特征值准确地绑定在一起。这就产生了最适合 MPP/OLAP 处理的复杂连接条件。
另一方面,需要实时数据管道来驱动 ML 模型,用于实时地直接对最终用户交互做出反应。一个例子是产品推荐引擎或下一个最佳行动模型,其中用户活动直接影响推理使用的特征值。在这种情况下,特征的源需要通过流或直接数据库插入或更新操作实时连接到特征存储。在处理这些消息/事务时,它们会及时生成新的特征值,以便后续的推理读取它们。这种操作通常一次只影响少量的行,但有可能产生非常高的并发性。
在许多情况下,用户交互可能涉及多个功能集。重要的是,当为了推断而读取时,所有的特征值都与用户最近的动作一致。这推动了对数据库引擎中保证这种一致性的 ACID 属性的需求。这些高并发、低延迟的工作负载最好由 OLTP 数据库引擎来处理,这些引擎可以随着用户和业务活动的增长而扩展。
很少有数据库同时支持这两种工作负载并提供水平可伸缩性。随着特征存储成为具有实时解决方案的机器学习平台中的标准实现模式,将需要这种规模的 HTAP 数据库。所以现在,商用拼接机就是这样一个数据库引擎,提供符合 ACID 的 OLTP 和 OLAP 引擎,它们可以独立伸缩。 Splice Machine 的特征库及其数据库内模型部署提供了一个完美的组合,可直接在特征库上提供实时和批量推理。
特色商店——什么、为什么、在哪里以及如何?
“功能商店”这个术语最近已经流传很久了。这篇文章试图阐明这个话题。
马库斯·温克勒在 Unsplash 上的照片
这篇文章正被移到我的 子栈发布 。这里 可以免费阅读文章 。这篇文章将于 2022 年 7 月 18 日被删除。
但是在我们去特色商店之前,
什么是特性?
特征是作为模型输入的独立属性。考虑模型
y = f(x)
这里 x 是你的输入向量, y 是你的输出向量, f 是你的模型。 x 中的每一列都是您的型号的特征。机器学习模型从特征中学习,并在训练期间更新其参数,以便能够对输出做出良好的预测。
现在,
什么是功能商店?
我是在参加 apply() 的时候被介绍到特色店的。简而言之,要素存储是存储要素的数据存储。听起来很直接,对吗?那么,为什么不直接创建一个 SQL 或 BigTable 数据库并完成它呢?是什么让特色店如此特别?嗯,实现是它的特别之处。因此,让我们看看为什么我们需要功能商店来理解这一点。
为什么选择特色商店?
为了理解我们为什么需要特征存储,我们需要知道机器学习生命周期的不同阶段是什么。下面列出了它们。
本文其余部分已移至出版物 机器学习—科学、工程和 Ops 。这里 可以免费阅读整篇文章 。
特性 101:特性集分析简介
关于如何更好地使用和理解功能的小指南
(src =https://pix abay . com/插图/统计-图形-图表-数据-3411473/ )
介绍
在极其复杂的数据科学世界中,有许多情况需要对数据进行分析。对任何数据科学家来说,分析数据都是绝对必要的技能。数据也需要以多种方式进行分析,而不仅仅是分析师可能采用的传统方式。这是熟悉数据如何工作,更重要的是统计和人工智能如何工作的重要垫脚石。
分析特征,尤其是第一次,可能是一项相当艰巨的任务。不要担心,因为最终这将成为容易的部分——它类似于一个新木匠。他可能会用他的黄铜锤敲几个钉子,毁掉他的第一把锤子,但他会有另一次机会,下次会用正确的锤子。我的观点是,即使这可能是压倒性的,我鼓励任何有抱负的读者坚持下去,因为它会变得更容易!事不宜迟,让我们深入了解一些特性。此外,您可以在这个笔记本中查看本文的代码:
https://github.com/emmettgb/Emmetts-DS-NoteBooks/blob/master/Julia/Analyzing Features.ipynb
特征类型
对于这个项目,我将使用 VegaDatasets.jl 中的“cars”数据集。
using VegaDatasets
data = dataset("cars")
现在,我们可以使用 DataFrames.jl 模块将该数据集包装成数据帧类型:
using DataFrames
df = DataFrame(data)show(df)
(图片由作者提供)
在我们开始研究这些特性之前,让我们先考虑一下我们拥有的不同类型的特性。意识到我们实际上正在使用什么类型的功能,以及关于这些功能的细节将有助于我们的机器学习。这是因为特性对模型有很大的影响,并且预处理可能会在模型使用之前发生。
绝对的
第一类特征是分类特征。分类要素是描述数据的某种分组方面的要素。例如,假设我们去一家经销店,我们要求一辆轿车,轿车是汽车的一种分类。这是汽车分类维度的一个例子。分类特征可以出现在几乎任何数据类型中,并且有一些方法可以尝试确定一个特征是否实际上是分类的,这些方法中的一种,可能是最有价值的,我们将很快使用。
二项式(布尔型,真或假)
二项式,二进制,布尔型,不管你想叫它们什么,它们通常用真和假,或者 1 和 0 来表示。
连续的
连续特征是具有某种定量值的特征。这些只能是某种抽象的数字数据类型,所以如果它不是某种数字,这是一个非常简单的方法来排除值不能是连续的。
其他的
每当特征不符合这些规范中的任何一个时,它们通常是标签。标签对于分析、日期确定和诸如此类的事情可能是有用的——但通常只能让人们更好地理解项目中可能实际使用的功能。然而,另一件要注意的事情是,我们有时可以将其中一些特性处理成其他类型的特性。例如,如果我们有一个日期,我们可以把它变成一年,并把这一年作为一个特征。这在技术上也被认为是特征工程,所以通过这样做,你听起来会比实际上更酷。
我们的特色
既然我们已经很好地掌握了不同类型的要素及其用于表示的内容,现在我们可以从上面的数据中查看这些要素,并尝试找出哪些要素是哪些要素。第一个特征
是“名字”名字很明显是一个标签,顾名思义(看到我在那里做了什么?)接下来,让我们跳过气缸。这可以作为一种测验来测试您的要素分析技能。那是什么类型的特征?保留这个答案,因为接下来让我们看看每加仑英里数。这是很多数字,它们的值波动很大。如果我们不确定,我们可以将集合类型投射到这个列上,看看与整个数据数组相比,集合中有多少观察值。马力和排量也属于同一范畴,因为它们显然符合我们对连续值的描述。
然而,我们还有一个特征要研究——圆柱体。如果你认为这个特征是连续的,那么对不起,但你实际上是不正确的!尽管是数字,但确实代表了实际的气缸数量,请记住,我们在这里讨论的是汽车。我们正在比较不同的方面,如排量和马力,所以在这种情况下,气缸数可能是三个数字之一,4,6 和 8。让我们将 set 类型转换为这个特性,看看会发生什么:
Set(df[!, :Cylinders])
(图片由作者提供)
我感到惊讶的是,他们设法在如此多种多样的发动机中进行了少得可怜的 4000 次观察。这实际上并不是最优的。如果我们用较少的专业知识来处理这个问题,我们可能会把它误认为是一个连续的特征。这是有问题的,因为我们可能会不小心降低模型的准确性。更糟糕的是,如果这是我们的目标,我们可能对这个应用程序使用了错误类型的模型。这就是为什么批判性地思考这些特性并通过屏幕上的数字尽可能地理解它们是如此重要。
性能
假设我们现在可以确定我们可能希望在我们的功能中搜索什么,知道如何处理它们,我们现在可以了解每种类型的功能的属性。当涉及到分类特征时,通常您会希望查看
- 设置
- max-key(出现次数最多的类别)
- 数据类型
说到连续功能,您会想看看
- 意思是
- 差异
- 标准偏差
当然,人们可能还想看到这两者的其他方面,但这些只是一些建议。这些当然是学习更多特定特性的良好开端。
结论
恭喜你!你正式成为功能专家了!特征是数据科学的一个非常重要的方面,这可能有点令人生畏,但是采用这样一种简单、有条不紊且经过深思熟虑的方法可以使这类事情变得容易得多。我希望这篇文章对您的数据科学之旅有所帮助!非常感谢您的阅读!
用于预处理文本数据的 FeatureUnion、ColumnTransformer 和 Pipeline
了解如何在 NLP 项目中应用这些工具
假设您已经使用矢量器(例如TfidfVectorizer
、CountVectorizer
)将文本数据预处理成矩阵,作为模型的准备。您可能会想到,导出其他特征(比如文档的长度)也可能对您的模型有用。虽然有许多可能的方法来组合这些预处理步骤,但是利用FeatureUnion
、ColumnTransformer
和/或Pipeline
可能是完成该任务的最佳方法之一。在本帖中,我们将通过几个例子来了解如何应用这些令人敬畏的工具(主要关注FeatureUnion
)。
虽然没有必要,但在阅读本文之前,对以下主题有所了解可能会有所帮助。
◻️TfidfVectorizer
t16】◻️Pipeline
、ColumnTransformer
和FeatureUnion
在这篇文章中,我们不会详细解释这些概念,因为它们会在下面两篇文章中解释。
相反,我们将直接进入他们的文本预处理应用程序!
0.设置和数据🔧
让我们从导入必要的库开始,并在餐馆评论上创建一个最小的可用玩具数据集:
保持较小的数据集将有助于更好地理解该过程,并更专注于实际 sklearn 工具的实际应用。
1.并联变压器
1.1.不带Pipeline
假设我们预处理的目标是对文本进行矢量化,并从文本中提取两个特征。更准确地说,我们希望做到以下几点:
◻️ ️Vectorise “文档”列带TfidfVectorizer
◻️️添加显示文本长度的功能带CharacterCounter
◻️️添加显示文本中字母数字标记数量的功能带TokenCounter
CharacterCounter
和TokenCounter
是我们将要创建的定制变形金刚。我们不能在单个Pipeline
中顺序地链接这三个,因为TfidfVectorizer
只将文本列作为输入,并输出一个没有原始文本列的稀疏矩阵。FeatureUnion
是这种情况下的完美工具。由于FeatureUnion
的行为就好像它创建了输入数据的副本,我们可以用并行转换器设计这样的预处理流程:
作者图片
每个流都接受相同的输入:X[‘document’]
,输出被连接起来。为了简洁明了,我们从这里开始将这些流称为流 A 、流 B 和流 C 。现在,让我们将流程翻译成代码:
Tada!我们已经使用FeatureUnion
对数据进行了预处理。
1.2.用Pipeline
让我们用Pipeline
来扩展我们之前的例子。这一次,我们将使用缩放器扩展流 B 和流 C 。换句话说,下面总结了我们的目标:
◻️️用TfidfVectorizer
向量化‘文档’列◻️️用CharacterCounter
添加显示文本长度的特征,然后用MinMaxScaler
缩放
◻️️用TokenCounter
添加显示文本中字母数字标记数量的特征,然后用MinMaxScaler
缩放
使用Pipeline
,预处理流程可以总结如下:
作者图片
管道给了我们灵活性,我们可以用更多的转换器来扩展任何流。虽然在本例中,两个流 B & C 使用相同的定标器,但它们不必相同,因为它们彼此独立。所以现在代码变成了:
正如我们所看到的,FeatureUnion
帮助我们保持预处理步骤有组织,并编写干净的代码。
2.顺序变压器
现在让我们看看从 1.1 节获得相同输出的另一种方法。我们可以不添加并联变压器,而是将流 B 和流 C 合并,并在Pipeline
中按如下顺序放置:
作者图片
为了让这个流程工作,我们需要调整我们的定制转换器,为它们创建一个名为counter_pipe
的管道,并更新preprocessor
:
我们可以用不同的方式设计预处理流程,同时仍然得到相同的结果。在这个特殊的例子中,我更喜欢 1.1 节中的方法。与这种替代方法相比。一般来说,这取决于用例以及个人偏好。
📍练习:尝试扩展上面的代码,从第 1.2 节获得相同的输出。
3.带列变压器
最后,这个例子是我最喜欢的,也是本帖中所有例子中最令人兴奋的一个。我们将利用所有三种工具:FeatureUnion
、ColumnTransformer
和Pipeline
,其中每一种工具都发挥着独特的作用,并相互补充。
实际上,数据包含文本和非文本列的情况并不少见。例如,文字评论也可能伴随着星级评论。在这种情况下,我们将研究如何对所有信息进行预处理,这样我们就不会丢弃潜在的有价值的信息。让我们用一些数字特征来扩展数据集。
现在我们预处理的目标是:
◻️️用TfidfVectorizer
向量化‘文档’列◻️️用CharacterCounter
添加显示文本长度的功能◻️️用TokenCounter
添加显示文本中字母数字标记数量的功能◻️️用‘has _ tipped’和‘rating’列使用SimpleImputer
中值,然后用MinMaxScaler
缩放它们
现在预处理流程可以如下所示:
作者图片
使用ColumnTransformer
,我们将数据集分成两个流。左侧流有一个带两个变压器的Pipeline
。右边的流与我们在第 2 节中看到的FeatureUnion
相同。使用我们在上一节中定义的转换器,我们可以这样定义新的流:
瞧啊。希望这展示了一个FeatureUnion,
ColumnTransformer
,Pipeline
如何和谐工作的实际用例。
4.结束语
熟练运用FeatureUnion,``ColumnTransformer``Pipeline
是数据科学家的一项有用技能。有了这些工具,预处理过程可以保持整洁有序。例如,对所有例子来说,预处理看不见的数据都是轻而易举的事情,可以用一行代码完成:preprocessor.transform(new_data)
。下面显示了第 3 部分的示例:
这看起来不是很优雅很专业吗?
我希望您喜欢学习如何以不同的方式应用这些工具!希望它对你当前或下一个 NLP 项目有用。
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接 ,成为会员,您的一部分会费将直接用于支持我。
感谢您阅读我的文章。这里是我的另一个可能感兴趣的帖子: Pipeline,ColumnTransformer 和 FeatureUnion 解释。
我所有博客的精简列表来自 here:️ 我的数据科学文章目录
再见🏃 💨
使用 Google 的 T5 文本到文本转换器来特征化文本
如何扩展特征工具 原语-函数 从表格文本列自动创建特征。
图片由 谷歌 提供。文本到文本框架图。每个任务都使用文本作为模型的输入,模型被训练生成一些目标文本。这允许相同的模型、损失函数和超参数跨越不同的任务集,包括翻译(绿色)、语言可接受性(红色)、句子相似性(黄色)和文档摘要(蓝色)。参见 用统一的文本到文本转换器探索迁移学习的极限
原载于 2021 年 3 月 29 日 https://blog.ccganalytics.com**的 。
在本文中,我们将演示如何使用 Google 的 T5 文本到文本转换器来特征化表格数据中的文本。您可以使用这个库中的 Jupyter 笔记本继续学习。
当试图在机器学习管道中利用真实世界的数据时,经常会遇到书面文本,例如,在预测房地产估值时,有许多数字特征,例如:
- “卧室数量”
- “浴室数量”
- "平方英尺的面积"
- “纬度”
- “经度”
- &等等…
但是也有大量的文字,比如在 Zillow 网站上的房地产列表描述中。这些文本数据可能包含许多有价值的信息,这些信息在其他情况下不会被考虑在内,例如:
- 提及开放式厨房/平面图
- 提到花岗岩柜台
- 提及硬木地板
- 提及不锈钢器具
- 提及最近的装修
- &等等…
然而,令人惊讶的是,许多 AutoML 工具完全忽略了这些信息,因为流行的表格算法(如 XGBoost)不能直接使用书面文本。
这就是功能工具 原始函数 的用武之地。Featuretools 旨在为不同类型的数据(包括文本)自动创建功能,然后这些功能可以被表格形式的机器学习模型使用。
在本文中,我们展示了如何扩展 nlp-primitives 库以用于 Google 最先进的 T5 文本到文本转换器模型,在这样做的过程中,我们创建了最重要的 nlp 原语特性,这反过来又提高了 Alteryx 博客自动特征工程的自然语言处理中展示的准确性。
关于 T5
对于任何不熟悉 T5 的读者来说,T5 模型是在谷歌的论文中提出的,题为用统一的文本到文本转换器探索迁移学习的极限,作者是科林·拉弗尔、诺姆·沙泽尔、、凯瑟琳·李、·纳朗、迈克尔·马特纳、周燕琪、和彼得·刘。以下是摘要:
迁移学习已经成为自然语言处理(NLP)中的一种强大技术,在迁移学习中,模型首先在数据丰富的任务上进行预训练,然后在下游任务上进行微调。迁移学习的有效性已经产生了各种各样的途径、方法和实践。在本文中,我们通过引入一个统一的框架,将每一个语言问题转换成文本到文本的格式,来探索自然语言处理中迁移学习技术的前景。我们的系统研究比较了几十个语言理解任务的预训练目标、架构、未标记数据集、迁移方法和其他因素。通过将我们的探索与 scale 和我们新的“庞大干净的爬行语料库”相结合,我们在涵盖摘要、问题回答、文本分类等许多基准上实现了最先进的结果。为了促进 NLP 迁移学习的未来工作,我们发布了我们的数据集、预训练模型和代码。
一个机器学习演示,使用拥抱脸 T5 来表征文本
罗纳德·里根在 1985 年《变形金刚》英国年会上遇见擎天柱。在 NLP 的背景下——Hugging Face Transformers 是一个自然语言处理库,一个 hub 现在对所有 ML 模型开放,支持库有 Flair 、 Asteroid 、 ESPnet 、 Pyannote 等等。
为了扩展用于 T5 的 NLP 原语库,我们将构建两个定制的TransformPrimitive
类。出于实验目的,我们测试了两种方法:
- 微调抱紧面 T5-底座
- 一个现成的拥抱脸 T5 模型为情绪分析预先调整
首先,让我们加载基本模型。
from simpletransformers.t5 import T5Modelmodel_args = {
"max_seq_length": 196,
"train_batch_size": 8,
"eval_batch_size": 8,
"num_train_epochs": 1,
"evaluate_during_training": True,
"evaluate_during_training_steps": 15000,
"evaluate_during_training_verbose": True,
"use_multiprocessing": False,
"fp16": False,
"save_steps": -1,
"save_eval_checkpoints": False,
"save_model_every_epoch": False,
"reprocess_input_data": True,
"overwrite_output_dir": True,
"wandb_project": None,
}model = T5Model("t5", "t5-base", args=model_args)
其次,让我们加载预调好的模型。
model_pretuned_sentiment = T5Model('t5',
'mrm8488/t5-base-finetuned-imdb-sentiment',
use_cuda=True)
model_pretuned_sentiment.args
为了微调t5-base
模型,我们需要重新组织和格式化用于训练的数据。
图片作者。原始 Kaggle 数据集
从 Kaggle 数据集中,我们将把review_text
列映射到一个名为input_text
的新列,并且我们将把review_rating
列映射到一个名为target_text
的新列,这意味着review_rating
是我们试图预测的。这些变化符合用于微调 t5 的 Simpletransformers 库接口,其中主要的额外需求是指定一个“前缀”,这意味着有助于多任务训练(注意:在本例中,我们关注的是单个任务,因此前缀是不必要的,但是为了便于使用,我们还是要定义它)。
dft5 = df[['review_text','review_rating']
].rename({
'review_text':'input_text',
'review_rating':'target_text'
},axis=1)dft5['prefix'] = ['t5-encode' for x in range(len(dft5))]dft5['target_text'] = dft5['target_text'].astype(str)dft5
输出。图片作者。
本例中的目标文本是消费者对给定餐馆的评分。我们可以通过以下方式轻松地微调此任务的 T5 模型:
from sklearn.model_selection import train_test_splittrain_df, eval_df = train_test_split(dft5)model.train_model(train_df, eval_data=eval_df)
接下来,我们加载预调好的拥抱脸模型。
from sklearn.model_selection import train_test_splittrain_df, eval_df = train_test_split(dft5)model.train_model(train_df, eval_data=eval_df)
让我们测试这两个模型,以更好地了解它们将预测什么。
test = ['Great drinks and food', list(np.array(model.predict(test)).astype(float))
'Good food & beer',Generating outputs: 0%| | 0/1 [00:00<?, ?it/s] Generating outputs: 100%|██████████| 1/1 [00:00<00:00, 3.17it/s] Generating outputs: 100%|██████████| 1/1 [00:00<00:00, 3.16it/s] Decoding outputs: 0%| | 0/3 [00:00<?, ?it/s] Decoding outputs: 33%|███▎ | 1/3 [00:00<00:01, 1.14it/s] Decoding outputs: 100%|██████████| 3/3 [00:00<00:00, 3.43it/s] Out[14]: [4.0, 4.0, 4.0]
'Pretty good beers']
我们可以看到,微调后的模型输出了一个review_rankings
【4.0,4.0,4.0】的列表,这是试图预测我们问题的最终答案。
接下来,我们用预先调好的拥抱脸模型做一个测试预测。
test = ['Great drinks and food',
'Good food & beer',
'Pretty good beers']list(np.where(np.array(model_pretuned_sentiment.predict(test))=='positive', 1.0, 0.0)) Generating outputs: 0%| | 0/1 [00:00<?, ?it/s] Generating outputs: 100%|██████████| 1/1 [00:00<00:00, 7.57it/s] Generating outputs: 100%|██████████| 1/1 [00:00<00:00, 7.56it/s] Decoding outputs: 0%| | 0/3 [00:00<?, ?it/s] Decoding outputs: 33%|███▎ | 1/3 [00:00<00:01, 1.17it/s] Decoding outputs: 100%|██████████| 3/3 [00:00<00:00, 3.50it/s] Out[15]: [1.0, 1.0, 1.0]
请注意,预调优的模型输出一系列布尔真/假值,这些值指示语句是positive
还是negative
——我们将这些值转换为浮点值,以便更好地与表格建模集成。在这种情况下,所有值都为真,因此输出变为[1.0,1.0,1.0]。
现在我们已经加载了 T5 的两个版本,我们可以构建TransformPrimitive
类,它将集成 NLP 原语和 Featuretools 库。
from featuretools.primitives.base import TransformPrimitive
from featuretools.variable_types import Numeric, Text class T5Encoder(TransformPrimitive):
name = "t5_encoder"
input_types = [Text]
return_type = Numeric
default_value = 0
def __init__(self, model=model):
self.model = model def get_function(self): def t5_encoder(x):
model.args.use_multiprocessing = True
return list(np.array(model.predict(x.tolist())).astype(float))
return t5_encoder
上面的代码创建了一个名为T5Encoder
的新类,它将使用经过 微调的 T5 模型,下面的代码创建了一个名为T5SentimentEncoder
的新类,它将使用经过 预调的 T5 模型。
class T5SentimentEncoder(TransformPrimitive):
name = "t5_sentiment_encoder"
input_types = [Text]
return_type = Numeric
default_value = 0
def __init__(self, model=model_pretuned_sentiment):
self.model = model def get_function(self): def t5_sentiment_encoder(x):
model.args.use_multiprocessing = True
return list(np.where(np.array(model_pretuned_sentiment.predict(x.tolist()))=='positive',1.0,0.0))
return t5_sentiment_encoder
Featuretools 现在将知道如何使用 T5 来特征化文本列,它甚至会使用 T5 输出来计算聚合,或者对其执行操作,例如从其他特性中减去该值。定义了这些新类后,我们只需将它们与默认类一起以所需的 Featuretools 格式进行汇总,这将使它们可用于自动化特征工程。
trans = [
T5Encoder,
T5SentimentEncoder,
DiversityScore,
LSA,
MeanCharactersPerWord,
PartOfSpeechCount,
PolarityScore,
PunctuationCount,
StopwordCount,
TitleWordCount,
UniversalSentenceEncoder,
UpperCaseCount
]ignore = {'restaurants': ['rating'],
'reviews': ['review_rating']}drop_contains = ['(reviews.UNIVERSAL']features = ft.dfs(entityset=es,
target_entity='reviews',
trans_primitives=trans,
verbose=True,
features_only=True,
ignore_variables=ignore,
drop_contains=drop_contains,
max_depth=4)
正如你在下面的输出中看到的,Featuretools 库非常强大!事实上,除了这里展示的 T5 特性,它还使用指定的所有其他 NLP 原语创建了数百个特性,非常酷!
feature_matrix = ft.calculate_feature_matrix(features=features,
entityset=es,
verbose=True)features
- <feature: t5_encoder=""></feature:>
- <feature: t5_sentiment_encoder=""></feature:>
- <feature: restaurants.max=""></feature:>
- <feature: restaurants.max=""></feature:>
- <feature: restaurants.mean=""></feature:>
- <feature: restaurants.mean=""></feature:>
- <feature: restaurants.min=""></feature:>
- <feature: restaurants.min=""></feature:>
- <feature: restaurants.skew=""></feature:>
- <feature: restaurants.skew=""></feature:>
- <feature: restaurants.std=""></feature:>
- <feature: restaurants.std=""></feature:>
- <feature: restaurants.sum=""></feature:>
- <feature: restaurants.sum=""></feature:>
机器学习
现在,我们使用包括新创建的 T5 原语的特征矩阵来创建和测试来自 sklearn 的各种机器学习模型。
提醒一下,我们将比较 T5 增强的准确性和 Alteryx 博客中展示的自动化特征工程的自然语言处理的准确性。
使用逻辑回归:
请注意,上面的 0.64 逻辑回归分数显示了对 Featuretools 原生逻辑回归分数(0.63)的改进。
使用随机森林分类器:
请注意,上面的 T5 增强的 0.65 随机森林分类器分数显示了对 Featuretools 原生随机森林分类器分数(0.64)的改进。
随机森林分类器特征重要性
我们可以使用 sklearn 随机森林分类器特征重要性将改进的分数归因于新的 T5 基元。
随机森林要素重要性。作者图片
从上表中我们可以看出,随机森林模型的最高特征重要性是新创建的特征
T5 _ 情操 _ 编码器(评论 _ 标题)!
随机森林分类器特征重要性,图片由作者提供
关键要点
- T5 模型是一个健壮、灵活的文本到文本转换器,它可以增强几乎任何 nlp 任务的结果,包括那些 NLP 原语库在处理文本数据时处理的结果。额外的准确性,虽然在这里是微不足道的,但几乎肯定可以通过实现情感分析之外的额外拥抱面部预调整模型来提高。此外,在这个例子中,我们的微调 T5 版本只在
review_text
数据上进行训练,而不是在review_title
数据上进行训练,这似乎与 Featuretools 创建的功能不一致——这意味着所有创建的功能似乎只使用review_title
数据作为微调模型的输入,因此其性能更差。纠正这个问题很可能意味着更好的整体性能。 - 使用拥抱面部变形器和简单变形器库,扩展 Featuretools 框架很简单。通过加入一些额外的代码行,准确性提高了,而代码的复杂度保持不变。
最后的想法
大多数企业都有大量的表格数据,其中大部分数据都是书面文本格式的。CCG 是一家数据和分析公司,帮助组织变得更加洞察驱动。我们通过行业特定的解决方案解决复杂的挑战并加速增长。我们的数据科学团队使企业能够获得更大的可见性并做出明智的决策,从而获得竞争优势。我们的战略产品旨在加快价值实现,改善业务成果,并围绕可信见解的共同观点团结团队。请联系我们,帮助您构建下一个定制的 NLP 解决方案…
原载于 2021 年 3 月 29 日【https://blog.ccganalytics.com】。
CCG 是一家数据和分析公司,通过行业特定的解决方案,帮助组织变得更加洞察驱动,解决复杂的挑战并加速增长。我们让客户能够更好地了解他们的业务,做出明智的决策,从而获得竞争优势。我们的 战略产品 旨在加快价值实现、改善业务成果,并围绕可信见解的共同观点团结团队。
二月版:数据科学有趣的一面
月刊
提醒你去做你喜欢的项目
数据科学让你发现你周围的世界。如果你有一台笔记本电脑、无线网络和一个想法,它的工具和概念将使你能够回答你感兴趣的问题。你有没有想过在所有的朋友中谁最受欢迎?你对音乐的品味是否无聊?或者你是否能预知灵异事件?数据科学帮助你找到答案。当你研究一个对你来说很重要的主题或数据集,你对它充满热情,你自称是这方面的专家,这会带来很多快乐。
围绕数据科学的大部分对话似乎都集中在工作上,这是可以理解的。成为或成为一名数据科学家通常意味着你想成为或正在专业地从事这项工作,解决业务问题,并拥有“数据科学家”或类似的头衔。
然而,当你专注于转行、获得新工作或晋升的职业目标时,你可能会忽略是什么让数据科学如此令人愉快。这可能会变成一件苦差事。你可能只会把它与学习的压力和职业发展的压力联系在一起。尤其是在像这样充满挑战和不确定的时期——大多数休闲活动都受到限制或停止——休息一下,对自己有耐心,试着花时间在你喜欢的事情上是很重要的。
下面的帖子可以提醒你数据科学项目是多么有趣。这些例子可以启发你的下一个副业。它不一定要教你一项新技能。你不需要拯救世界。你可以享受你创造新事物的能力,去回答你关心的问题,去探索你周围的世界。
《走向数据科学》的编辑助理朱莉娅·尼库尔斯基
NLP on The Office 系列
由克里斯托夫·拉贝 — 17 分钟阅读
利用文本挖掘技术,如标记化、tf-idf 和情感分析来分析电视连续剧的脚本。
人工智能如何帮助我赢得对抗鸽子的战争
到 Tatiana Sennikova — 5 分钟读取
建筑概述和为什么你可能需要一个鸽子火绒
梵高用深梦卷积网络作画
由迭戈·萨利纳斯——4 分钟阅读
用 Tensorflow Deep Dream 进行计算机视觉的深度学习
漫威宇宙探索性网络分析
通过托马兹·布拉坦尼克 — 15 分钟读取
在图形数据科学库中引入新的 k-最近邻算法
利用无监督学习生成 Spotify 播放列表
通过卡勒姆·巴拉德 — 6 分钟读取
人工智能能区分愚蠢的朋克和混蛋吗?
用 Python 把照片变成漫画
通过 Tazki Anida Asrul — 4 分钟读取
你可以通过在 Python 中实现机器学习算法来给一张照片赋予卡通效果。
使用社区检测算法理解《权力的游戏》世界
基思·麦纽提 — 7 分钟阅读
社区检测算法非常准确,而且非常容易使用
谁是漫威电影中最重要的人物?
由迈克尔·陶伯格 — 7 分钟阅读
MCU 的数据分析(或者为什么钢铁侠可能值得他的百万身价)
新播客
- 海伦·托纳— 人工智能的战略和安全含义
- 欧文·埃文斯— 预测人工智能的未来
- 华金·基诺内罗·坎德拉— 脸书负责人艾
- Silvia Milano — 推荐系统的伦理问题
我们也感谢最近加入我们的所有伟大的新作家塞拉·斯坦顿、马克斯·埃利希、阿尔韦托·罗梅罗、埃布鲁·库岑、纳西娅·恩塔拉、曼努埃尔·乌尔塔多、亚历克斯·鲍威尔、宜兴关、塔加特·邦汉姆、克洛伊·摩根、 https://medium.com/u/1e1a852762e2?source=post_page-----4178e4d324ab-------------------------------- 何塞·曼努埃尔·纳波尔·杜阿尔特,钱丹·杜吉娅,凯蒂·莫里斯·克拉沃,KK·严(博士),罗比·盖根,阿尤什·库马尔,布鲁诺·席尔瓦,保罗·沃什,图,法布里奇奥·迪·瓜尔德 我们邀请你看看他们的简介,看看他们的工作。
通过基于距离的聚类进行联合学习
隐私没得商量
作者照片
你有没有想象过你的手机键盘是如何预测下一个关键词笔画的?
单词的工作/预测由部署在您的手机上的 ML 算法给出,并根据您的本地数据进行训练。由于它是对你的数据进行训练,你现在可能会有一个问题,我的隐私没有丢失吗?
答案是否定的。这些科技公司使用 联合学习 来解决隐私问题,因为没有数据被发送到主模型。相反,ML 模型将部署在您的设备上,并根据可用的数据进行训练,然后返回模型参数而不是数据。让我们深入了解它的工作原理,在本文中,我们提出了一种新的方法来对相似的设备进行聚类,以提高模型的性能。
内容列表:
- 介绍
- 联合学习
- 我们的框架
- 使聚集
- 培训阶段
- 结果和比较
- 结论
F 深度学习(FL)是一种系统架构,它利用手机等分布式网络来增强 AI 模型性能,同时对其所有者保密个人数据。本文提出了一种对传统 FL 设计的新颖补充,它利用集群将相似的设备分组,并在训练期间增强彼此的协作。
1.简介:
联合学习是一种范例,其中建立了一个分布式设备系统来协作训练模型。传统的联合学习涉及具有包含模型权重的中央服务器,该中央服务器具有通过偶尔将权重发送回服务器来帮助训练该模型的设备。当权重被发送回服务器时,所有设备都有均等的机会使用称为联合平均的过程来更新主/服务器模型( FedAvg )。用简单的术语来说,它可以被认为是一组值的平均值。
如果你不熟悉几个术语,不要惊慌。我们将从头开始学习它们。
一旦应用了 FedAvg,就用它来更新集中式模型,然后将更新后的权重广播给网络中的所有设备。
传统方法的问题在于,它严重依赖于所有设备都将以类似方式学习的假设。然而,现实地说,设备将使用不同的数据集进行操作,每个数据集代表由 f1 表示的整个模型的子集。
因此,平均设备重量不太可能是最佳方法,因为它忽略了设备间不平衡数据引起的偏差。因此,在我们的实践中,我们以不同的方式看待问题。我们看到,除了只有中央模型,我们还可以引入聚类的概念,表示表现出相似学习行为的不同设备的组。通过进行这种聚类,我们认为在聚类级别上应用的算法(如 FedAvg)应该强调对其中的设备最重要的权重更新。
在本文中,我们将看到一个三阶段实验来探索我们的聚类方法。以下是我们所做工作的总结:
第一阶段:
- 跨多个设备分割目标数据集
- 使用传统的外语学习方法训练所有设备
- 第二阶段:
- 基于阶段 2 之后的设备权重,我们运行两种聚类算法。聚类算法输出一个聚类列表,每个
聚类都有一个属于它的设备 id 列表。每个群集通过平均所有设备的权重来计算自己的权重。 - 进一步训练设备,但不是将它们的重量报告回中央服务器,而是仅将它们报告给它们的集群。因此,这实际上创建了多个传统的 FL 网络,其中每个网络代表一个集群以及属于该集群的设备子集。
第三阶段:
- 我们计算阶段 2 完成后生成的权重的多个排列,然后使用它来评估应用聚类后模型的改进。
2.联合学习:
机器学习算法,尤其是深度学习算法,需要大数据集才能有效训练。在现实世界中,数据在隐私限制下分布在多个组织中。此外,有许多部门的数据不能在内部共享,如政府、金融、医院和研究实验室,由于数据法规和政策的原因,内部协作是不可能的。然而,如果这些实体能够在保持其数据匿名的同时进行合作,我们就可以将我们的模型暴露给丰富多样的数据集。
为了适应这些限制,需要一种无需交换用户数据的协作学习解决方案。该解决方案是通过结合联邦和机器学习提出的,它被称为联邦学习(FL)。在一般的机器学习中,数据存在于单个设备或数据中心,这些算法使用这些数据并在其上建立模型。
然而,如果你看看下面的图片,在 FL 中,服务器将模型发送到其网络中的各个设备,并根据每个设备的数据进行训练。训练完成后,仅返回模型参数,而数据保留在拥有它的设备上。因此,服务器聚合所有客户端的结果,并使用 FedAvg 执行聚合。
有机会使用模型参数来确定模型行为。因此,可以计算安全聚合来克服这个问题,其中从客户端获得的模型参数被加密,而服务器模型只能解密聚合。以下是外语培训过程的概述。
传统 FL:作者照片
一次外语训练通常要进行四个步骤。
- 第一步,在集中式服务器上选择机器学习模型。
- 接下来,这个模型被传播到所有的网络设备(在上图中,是 4 个设备)。
- 每个设备在第三步中开始训练模型,并开始具有反映其数据的唯一权重。
- 最后,在步骤 4 中,它们将自己的权重发送回服务器,在服务器中进行联合平均,然后将结果广播给所有设备。这四步算一轮 FL 训练。
我们在我们的项目中使用了 TensorFlow Federated ,这是一个允许分散数据计算的机器学习框架。这个开源框架将使用户能够研究和构建基于 FL 架构的模型。
3.我们的框架:
我们的框架已经建立,以比较提出的多阶段模型和一个香草 FL 模型。因此,这两个模型是我们研究框架的两个组成部分。这两种型号都被配置为运行在 E epochs 上,并且在其网络中包含 100 个设备。网络中的每个设备包括数据集的随机分布。
数据集:
对于数据集,使用 10 重交叉验证,指标是召回率和准确度。
em NIST:
tensor flow em NIST 可以被视为 MNIST 数据集,其中有 10 个类别标签(0–9)。它包含 60,000 个训练样本和 10,000 个测试样本。Tensorflow federated 提供了将数据集分发到多个客户端的方法,在此实现中,它用于在客户端之间拆分数据集。这可以在下图中看到,其中数据分布在多个客户端上。从图中我们可以看出数据分布不均匀(不平衡)。Tensorflow federated 允许我们将数据分成等量(平衡的)。在我们的研究中,我们根据训练后获得的数据分布和权重,使用不平衡数据对设备进行聚类。
数据在客户端的分布图片由 Google FL 提供
4.聚类:
我们提出的模型的基本部分是设备的https://en.wikipedia.org/wiki/Cluster_analysis群集。集群可以被认为是组合相似的设备。它允许设备从来自具有相似学习特征的设备的附加协作层中受益。例如,假设 EMNIST 数据集正被用于训练,并且两个设备可能具有大量学习识别数字 5 类别标签的经验。通过分享他们的体重,他们可以理想地帮助彼此以更快的速度学习。聚类发生在我们模型的第二阶段,并且在第二和第三阶段进行的训练中起着重要作用。在我们的研究中,我们测试了两种聚类方法。
- K-Means 聚类:
K-Means 算法( scikit learn,2020 )是一种为一组特定输入点创建聚类的成熟方法。该算法采用这些输入点,并且输入整数 K. K 表示要形成的聚类的数量。
算法:
在给定的算法 1 中,让 X 表示输入点的集合。
K 均值聚类算法:Ibrahim Helmy
关键特征:
这种聚类方法有几个重要的特征。第一个与设备可以包含在其中的集群数量有关。使用 K-means 聚类,一个设备一次只能是一个聚类的一部分。另一个关键特征是聚类的数量,K 变量,一个预定义的整数。这意味着集群的数量不能动态增加或减少。该整数必须是一个微调的超参数,根据所使用的数据集
和设备数量,该参数最好是一个不同的值。
更新设备重量:
在模型训练期间,群集中的每个设备在特定点接收更新。对于这种群集方法,每个设备的权重被设置为共享其群集的每个设备的所有权重的平均值。
2. 基于距离的动态聚类
第二种聚类方法是基于动态距离的聚类方法。对于这种方法,我们执行多个操作来获得最终的聚类列表。首先,所有设备之间的欧几里德距离是根据它们的权重计算的
。其次,确定阈值。该阈值用作集群中包含的两个不同设备之间的最大距离。一旦选择了该值,算法就开始聚类过程。在我们的研究中,阈值被设置为所有聚类权重的平均值。算法 2 对此进行了更详细的描述。
基于动态距离的聚类算法:作者 Ibrahim Helmy
示例:
让我们把这个 Python 字典看作一个设备和所有其他设备的地图,这些设备都在先前定义的阈值距离之内。python 字典中的键是“:”前面的值,值是后面的元素。关于下面的例子,
“1”是一个键,“[9,10]”是它的值。
{0: [],1: [9,10],2: [9],3: [],4: [],5: [9],6: [],7: [],8: [],9: [1,2,5],10: [1]}
在这里的例子中,字典的关键字是设备 id,值是距离设备最多阈值距离的设备的设备 id 列表。使用算法 2,聚类的结果列表将如下:
[[5,9],[9,1],[10,1],[2,9],[0],[3],[4],[6],[7],[8]]
关键特征:
如前面给出的示例所示,与 K-Means 聚类不同,结果显示单个设备可以是多个聚类的一部分。这是一个独特的属性,它将允许一个设备与共享多个学习特征的其他设备协作,而不会受到它们彼此
不相似的限制。**
还需要注意的是,尽管允许一个设备成为多个集群的一部分,但是该方法的算法不允许子集。甚至未能成为组集群的一部分的设备形成它们自己的集群。
更新设备权重:
由于使用这种方法,单个设备可以是多个集群的一部分,因此设备权重是单独计算的,而不是在集群中计算的。每个设备的权重被更新为其所属的每个集群的所有权重平均值的平均值。使用上述示例中的集群列表,设备 9 的更新如下:
设备 9 新权重= Avg( Avg([5,9]),Avg([9,1]),Avg([2,9]))
5.培训阶段:
阶段 1 —初始化
第一阶段:穆斯塔法·卡特吉拍摄的照片
这个阶段是为了初始化我们的实验。
它由传统的 FL 模型组成,其中 N 个设备在“e”个时期内进行训练,并通过 FedAvg 在集中式 FL 模型上进行协作。在训练期间,集中式 FL 模型也将向所有设备广播重量更新。在“e”时代完成后,每个设备将具有唯一的权重,该权重来自与其他设备的协作,并且非常适合该设备的数据集。我们跟踪第 2 阶段的单个设备重量,并评估该模型的总体性能。
第 2 阶段——集群培训:
第二阶段:穆斯塔法·卡特吉的照片
在这一阶段,我们将介绍我们对集群培训的贡献。
使用来自阶段 2 的单个设备权重,我们使用 K-means 和基于距离的聚类对它们进行聚类。对于每种聚类算法,我们得到一组不同的设备聚类。
然后,我们将每个设备群集视为其自己的 FL 模型,其中群集的中心模型使用群集的平均设备权重进行初始化。之后,我们为每个集群的“e”时期训练设备,这最终导致更新的中央集群权重。
因此,群集鼓励在阶段 1 中进行类似训练的设备严格协作。这与传统的 FL 训练相比是有利的,在传统的 FL 训练中,不相关的设备相互影响,这可能损害它们各自数据集的性能。
第 3 阶段—评估:
在这一步中,我们通过评估从阶段 2 中探索的聚类方法得出的最终权重来评估我们的聚类方法的有效性。
- 我们以三种不同的方式评估新的权重:
- 所有权重的平均值在通用测试集上的表现如何?
- 所有权重的加权平均值在通用测试集上的表现如何?
-每个聚类权重使用其达到的最高精度进行加权
-如果我们通过取其权重和所有聚类的平均值之间的平均值来更新每个聚类权重,那么每个聚类是否仍然保留
其专业性,但也通过受益于其他聚类来获得更好的泛化能力?
-该评估使用每个集群设备的测试集。
6.结果和比较
评估指标:
用于评估的指标是准确度和精确度。TFF 的联邦学习 API 层提供了可以直接在张量流模型中使用的高级接口。然而,它只返回一个精度分数,并且使用这个 API 层不可能获得精度值。为了得到召回分数,TFF 的联邦核心 API 层可以作为构建 FL 的基础。它提供了一组低级接口,因为它允许用户通过改变函数式编程环境来执行计算。
为全局模型分割一个测试集,并且跨每个客户端分布唯一的测试集。对全局模型和局部更新模型的评估是用它们独特的测试集来执行的。对测试集执行以下评估,并记录结果:
客户端和全局模型的准确性(第 1 阶段)
;聚类平均值更新后的全局模型的准确性(第 3 阶段)
;加权聚类平均值更新后的全局模型的准确性(第 3 阶段)
;聚类平均值更新后的客户端的准确性(第 3 阶段)
还报告了具有 K 均值和基于动态距离的聚类的模型的结果。
与之前的作品形成对比:
实验中使用的分层聚类技术具有不同的因素,如聚类前的通信回合数、不同的非 iid 设置、距离度量,如 L1、L2、余弦距离。
记录参与的客户数量、通信回合、客户的测试准确度以及达到目标测试准确度的客户的百分比。要注意的是,没有报告聚类步骤之后的全局模型的性能。
以下是本文呈现的新颖之处:
- 聚类技术—使用 K 均值和动态距离聚类。
- 所有客户都参与学习过程。
- 聚类后,局部模型没有用当前全局状态初始化。相反,用于聚类的权重同样用于进一步的基于聚类的训练。
- 聚类是独立训练的,没有对全局模型的任何反馈。
- 第 3 阶段在本文中介绍,其中全局模型以两种不同的方式更新—聚类平均和加权聚类平均。客户端使用其所属的集群和所有其他
集群的平均权重进行更新。
中央服务器和客户端使用卷积神经网络在 EMNIST 数据集上进行训练。数据被分发给 100 个具有非 iid 设置的客户端。阶段 1 执行 20 个时期,随后是阶段 2 聚类训练 20 个时期。SGD optimizer 的学习率为 0.1。
在所提出的方法中,欧几里德距离用于计算相似性,并且计算设备到设备的距离。因此,L2 和单一连锁结果被认为是一个公平的比较。由于报告了客户的最高测试准确度和达到该准确度的客户的百分比,因此也报告了所提议的方法。表 1 描述了 L2 距离、单个链接设置的结果。以下是从实施建议的方法中观察到的结果。
图表作者:Rajitha Muthukrishnan
7.结论:
观察了联邦学习中的培训过程的概述,并提供了基线学习如何工作以及它与具有两个数据集的多阶段方法的比较。后者取得了比基线 FL 更好的结果,因为聚类允许相似的设备相互训练。
同样,相同的设备形成集群,影响其性能的无关设备被分离。因为单个设备可以是多个集群的一部分,所以它比传统的集群方法产生了更好的结果,在传统的集群方法中,一个设备可以是单个集群的一部分。在没有对全局模型的任何反馈的情况下独立地训练聚类产生了更好的结果。FL 是一个热门的研究课题,用置信区间或由此衍生的其他方法扩展聚类方法将是一个强有力的研究方向。
这篇文章是基于与 Ibrahim Helmy 、 Mostafa Katerji 和 Rajitha Muthukrishnan 一起进行的研究。
感谢阅读到最后。如有错误或建议,欢迎不吝赐教。
如果你想联系我,请通过 LinkedIn 联系我。
参考资料:
****https://www.tensorflow.org/federated https://ai.googleblog.com/2017/04/federated-learning-collaborative.html ****
联合学习:你的数据与你同在
通过联合学习,我们可以在不共享用户数据的情况下,以另一种方式提高集中式机器学习模型的性能。
约翰·萨尔维诺在 Unsplash 上拍摄的照片
这是 21 世纪,“数据是新的黄金”。随着新技术的出现,更高的计算能力,当然还有大量的数据,人工智能获得了很大的发展势头,全球人工智能(AI)市场预计将从 2021 年的 583 亿美元增长到 2026 年的 3096 亿美元,根据 MarketsandMarkets 的预测,预测期内的复合年增长率(CAGR)为 39.7%。
虽然人工智能给我们的日常生活带来了很多舒适,但我们甚至没有意识到这一点,也存在一些挑战。数据隐私就是其中之一。应用程序收集你的数据(当然不会卖给第三方应用程序,是吗?)为您提供更个性化的推荐和结果(以及广告😐).
那么问题来了,数据离开你的手机了吗?
答案是肯定的。例如,当您授权任何应用程序访问您的位置信息时,它会收集您的位置数据。现在取决于应用程序,他们希望他们的人工智能算法如何使用它。有两种选择:
- 在服务器上:机器学习/深度学习模型部署在服务器上,在服务器上,它根据从数十亿部智能手机接收的数据训练模型。
- On-device:ML/DL 模型部署在手机上,用户数据用于训练和改进模型以获得更好的推荐。
两者各有利弊。在服务器上进行培训需要大量的存储空间来存储数据,并需要世界一流的安全性来保护他们免受数据泄露的影响。而设备上训练是在有限的数据量上训练的,并且模型性能受到损害。
解决方案:在分散数据上训练集中模型。嘣!!!!
好的,让我解释一下。
为了获得更好的用户体验,一家公司将希望来自数十亿部智能手机的数据在服务器中的一个集中模型上进行训练。但为此,数据必须离开智能手机。但是我们不想那样,对吗?相反,如果在进行训练的所有设备中都存在集中式模型的副本,那么我们已经解决了性能问题。现在,我们不得不将来自每部智能手机的所有结果整合到一个单一的结果中。现在,训练结果(我们机器学习工程师称之为:【权重】显然可以发送到服务器,在那里进行合并。现在,权重被高度加密,密钥取决于设备上的模型。
哦耶!!!
并且为了进一步改善用户隐私,使用安全聚合协议,该协议使得服务器能够组合加密结果,仅通过添加零和掩码来解密该聚合。要了解更多相关信息,请参考这篇文章。
最后,总重量被发送回设备上的模型,我们现在有一个新的改进的模型更新。
每一个新的开始都会带来新的挑战。相信新挑战的美丽,它们会帮助我们成长。
让我们来讨论一下挑战。
- 有些数据是特定用户专用的。这将降低整个模型的性能。我们不希望模型记住来自特定用户的稀有数据。
解决方案:a)通过设计一种机制来控制单个用户对整体结果的贡献量。b)通过向更具体的数据添加噪声。这也被称为差分隐私。我发现这篇文章挺直观的。
2.现在我们有了从汇总结果中形成的新模型。但是,在推出更新之前,我们如何才能看到模型在新数据上的表现呢?
解决方法:简单!我们可以应用我们都知道的相同的训练验证分割概念。相反,在这里我们将用户作为我们的实验!!!!听起来很有趣,嗯?我们将用户分为训练和验证。在智能手机用户中,我们有一小部分人会验证这个结果。其余的将训练模型。因此,该模型在实时数据上进行了测试。
3.简单的平均聚合适用于所有算法吗?让我们用两个例子来解释这一点:
a)我们就拿正态贝叶斯(openCV) 来说。平均向量和协方差矩阵受每类样本数量的影响很大。现在,假设我们有两部智能手机和一个二进制分类问题,其中A 类和b 类
用户 1:
图片作者:包含三个 A 类样本和一个 B 类样本
用户 2:
图片作者:包含 3 个 B 类样本和 1 个 a 类样本。
其中 x ki ( j )表示训练样本中属于类别 k 的第 j- 个样本的第 i- 个特征属性的值,最后的n-维(共 n 个特征属性)类别 k ' μk' 的均值向量估计为:
因此,平均向量的值很大程度上受每类样本数量的影响。所以用户 1 的平均向量 μA(1) 具有类别 A 的 75%影响,而 μA(2)具有 25%影响。那么当我们通过取平均值 1/2(μA(1)+μA(2))来合并它们时,我们能够保留特定于类的信息吗?
b)对于像 SVM 这样的算法,其权重只不过是依赖于数据集中样本数量的支持向量,我们可以有一个对于所有结果大小不变的权重矩阵吗?我们可能需要专门针对机器学习任务的聚合算法。
4.隐私和准确性之间的权衡:
有时为了增加用户数据的隐私,会添加一些噪声,导致数据偏离其实际行为,从而导致一些准确性下降。
结论:
联合学习可以解决很多与用户隐私相关的问题,同时提高模型性能以获得更好的推荐。这是一个相当新的领域,更多的研究可以解决我们称之为协作学习所面临的许多挑战。
参考资料:
https://ai.googleblog.com/2017/04/federated-learning-collaborative.html https://arxiv.org/abs/1610.05492 https://www.tensorflow.org/federated
前馈神经网络——如何在 Python 中成功构建它们
神经网络
使用真实数据的 Python 示例对神经网络进行了详细的图形说明
前馈神经网络。图片由作者提供。
简介
神经网络已经成为过去几年的中心话题。虽然它们最初看起来令人生畏,但我向你保证,你不需要博士学位就能理解它们是如何工作的。
在本文中,我将带您了解基本神经网络背后的主要思想,也称为前馈神经网络或多层感知器(MLPs),并向您展示如何使用 Tensorflow 和 Keras 库在 Python 中构建它们。
内容
- 前馈神经网络在机器学习领域中的地位
- 直观解释前馈神经网络如何工作
-网络结构和术语
-参数和激活函数
-损失函数、优化器和训练 - 如何建立和训练你自己的前馈神经网络的 Python 例子
前馈神经网络在机器学习领域中的地位
机器学习是一个巨大且不断扩展的空间,每天都有新的算法开发出来。我试图通过在下面的交互式图表中对一些最常用的算法进行分类,来给这个世界带来结构。点击不同类别,放大并展示更多内容。👇
虽然这种分类并不完美,但它让我们大致了解了不同部分是如何组合在一起的,并且希望它还能促进您的数据科学学习之旅。
我将神经网络放在一个独特的类别中,认识到它们对机器学习的独特方法。然而,重要的是要记住,神经网络最常用于使用带标签的训练数据来解决分类和回归问题。因此,另一种方法是将它们置于机器学习的监督分支之下。
机器学习算法分类。由作者创建的互动图表。
如果你喜欢数据科学和机器学习 ,请 订阅 每当我发表一个新的故事,你都会收到一封电子邮件。
直观解释前馈神经网络如何工作
结构和术语
首先,让我们熟悉一下神经网络的基本结构。
前馈(FF)神经网络的基本结构。图片由作者提供。
- 输入层 —包含一个或多个输入节点。例如,假设您想预测明天是否会下雨,并根据湿度和风速这两个变量做出决定。在这种情况下,第一个输入是湿度值,第二个输入是风速值。
- 隐藏层——这一层包含隐藏节点,每个节点包含一个激活函数(稍后将详细介绍)。注意,具有多个隐藏层的神经网络被称为深度神经网络。
- 输出层 —包含一个或多个输出节点。按照上面相同的天气预测示例,您可以选择只有一个输出节点生成降雨概率(其中> 0.5 表示明天有雨,而≤0.5 表示明天无雨)。或者,您可以有两个输出节点,一个用于降雨,另一个用于无雨。注意,您可以对输出节点和隐藏节点使用不同的激活函数。
- 连接 —连接不同节点的线称为连接。这些包含内核(权重)和偏差,这些参数在神经网络的训练过程中得到优化。
参数和激活功能
让我们仔细看看核(权重)和偏差,以了解它们的作用。为简单起见,我们创建一个基本的神经网络,它有一个输入节点、两个隐藏节点和一个输出节点(1–2–1)。
在前馈(FF)神经网络中如何应用权重和偏差的详细视图。图片由作者提供。
- 内核(权重) — 用于缩放输入和隐藏节点值。每个连接通常具有不同的重量。
- 偏差 —用于在通过激活功能之前调整缩放值。
- 激活函数 —将激活函数视为神经网络用来创建定制曲线以拟合训练数据的标准曲线(构建模块)。通过网络传递不同的输入值会选择标准曲线的不同部分,然后将这些部分组合成最终的定制曲线。
有很多激活功能可供选择,最常用的有 Softplus 、 ReLU 、 Sigmoid 。以下是神经网络中六种常用激活函数的形状和方程:
激活功能。图片由作者提供。
我们现在已经熟悉了核(权重)、偏差和激活函数,让我们使用相同的神经网络根据今天的湿度计算明天下雨的概率。
注意,我已经训练好了这个神经网络(见下面 Python 部分)。因此,我们已经知道了核(权重)和偏差的值。下图显示了 FF 神经网络如何获取输入值并产生答案(输出值)的逐步过程。
前馈(FF)神经网络执行的示例计算。图片由作者提供。
正如你所看到的,上面的神经网络告诉我们,今天 50%的湿度意味着明天有 33%的可能性下雨。
损失函数、优化器和训练
训练神经网络涉及一个被称为反向传播的复杂过程。我不会一步一步地解释反向传播是如何工作的,因为这是一个足够大的主题,值得单独写一篇文章。
相反,让我简要地向您介绍损失函数和优化器,并总结当我们“训练”一个神经网络时会发生什么。
- 损失 —代表真实值/标签和预测值/标签之间的误差“大小”。训练神经网络的目标是使这种损失最小化。损失越小,真实数据和预测数据之间的匹配越接近。有很多损失函数可供选择,最常见的有二进制交叉熵、分类交叉熵、均方误差。
- 优化器——是在反向传播中使用的算法。优化器的目标是找到最佳的核(权重)和偏差集,以最小化损失。优化器通常使用梯度下降方法,这允许他们迭代地找到权重和偏差的“最佳”可能配置。最常用的有 SGD 、 ADAM 、 RMSProp 。
训练神经网络基本上是通过训练数据来拟合自定义曲线,直到它尽可能地逼近该曲线。下图说明了特定情况下定制曲线的外观。该示例包含一组数据,随着输入值的增加,这些数据似乎在 0 和 1 之间翻转。
将曲线拟合到训练数据。图片由作者提供。
一般来说,激活函数的广泛选择加上我们希望添加尽可能多的隐藏节点的能力(假设我们有足够的计算能力)意味着神经网络可以创建任何形状的曲线来拟合数据。
然而,拥有这种极大的灵活性有时可能会导致数据过度拟合。因此,在使用模型进行预测之前,我们必须始终确保在测试/验证集上验证模型。
总结我们所学的
前馈神经网络接受一个或多个输入值,并在通过激活函数传递结果之前,使用核(权重)和偏差来应用变换。最后,我们得到一个输出(预测),这是通过训练优化的复杂转换集的结果。
我们通过训练数据拟合定制曲线来训练神经网络,以损失最小化为指导,并通过参数(核和偏差)优化来实现。
用 Python 构建和训练前馈神经网络
现在让我们找点乐子,建立我们自己的神经网络。我们将使用澳大利亚历史天气数据来训练一个神经网络,预测明天是否会下雨。
设置
我们需要以下数据和库:
- 来自 Kaggle 的澳大利亚天气数据(许可:知识共享,数据原始来源:澳大利亚联邦气象局)。
- 用于数据操作的熊猫和 Numpy
- Plotly 用于数据可视化
- 神经网络的 Tensorflow/Keras
- Scikit-learn 库用于将数据拆分成训练-测试样本,以及用于一些基本的模型评估
让我们导入所有的库:
上面的代码打印了本例中使用的包版本:
Tensorflow/Keras: 2.7.0
pandas: 1.3.4
numpy: 1.21.4
sklearn: 1.0.1
plotly: 5.4.0
接下来,我们下载并获取澳大利亚的天气数据(来源: Kaggle )。我们也做一些简单的数据操作,并为我们的模型导出新的变量。
这是数据的样子:
一段经过修改的 Kaggle 的澳大利亚天气数据。图片由作者提供。
神经网络
现在我们训练和评估我们的前馈(FF)神经网络。我对下面的代码做了大量的注释,以便让您清楚地理解每个部分的作用。因此,我不会在文章正文中重复同样的内容。
使用一个输入(湿度 3pm)
简而言之,我们是用今天下午 3 点的湿度来预测明天会不会下雨。我们的神经网络具有本文前面分析过的简单结构(1–2–1):一个输入节点、两个隐藏节点和一个输出节点。
有几点需要注意:
- 下面的代码执行两次验证,一次是对 X_train 数据的一部分(参见步骤 5 中的 validation_split ),另一次是对步骤 2 中创建的测试样本。当然,没有必要做两次,所以可以随意使用任何一种方法来验证您的模型。
- 数据是不平衡的(晴天比雨天多),所以我在步骤 5 中调整了 classes_weight。
训练前馈(FF)神经网络。Gif 图片由作者提供。
上述代码为我们的 1–2–1 神经网络打印了以下摘要和评估指标:
1–2–1 前馈(FF)神经网络性能。图片由作者提供。
请注意,这个模型的权重和偏差与本文前面的计算示例中的不同。这是因为 神经网络训练使用了优化器算法内的随机(random)方法。因此,每次重新训练时,您的模型都会有所不同。
现在让我们在图表上绘制预测曲线。
单输入神经网络生成的预测曲线。图片作者作者。
使用两个输入(风速和湿度 3pm)
让我们看看当我们使用两个输入(风速和湿度 3pm)来训练具有 2–2–1 结构的神经网络时,网络和预测是如何变化的。
通过训练一个具有 17 个输入和不同数量的隐藏节点的模型,您可以随时进行试验。
结果是:
2–2–1 前馈(FF)神经网络模型性能。图片由作者提供。
由于我们使用了两个输入,我们仍然可以可视化预测。但是,这一次我们需要一个 3D 图表来完成:
由具有两个输入的神经网络产生的弯曲预测曲面。图片由作者提供。
结论
神经网络并不像一开始看起来那么可怕。我真诚地希望你喜欢阅读这篇文章,并获得一些新的知识。
请使用本文提供的代码来构建您自己的神经网络。另外,你可以在我的 GitHub 库中找到完整的 Jupyter 笔记本。
在我努力让我的文章对读者更有用的时候,如果你能让我知道是什么驱使你阅读这篇文章,以及它是否给了你想要的答案,我将不胜感激。如果不是,缺少什么?
干杯!👏
T21【索尔·多比拉斯
如果你已经花光了这个月的学习预算,下次请记得我。 我的个性化链接加盟媒介是:
https://solclover.com/membership
您可能感兴趣的其他文章:
反馈校准方法
思想和理论
生物驱动的反向传播替代方案
由 Robina Weermeijer 在 Unsplash 上拍摄的照片
反向传播的简单、高效、高精度和收敛速度,使其成为训练神经网络的实际算法。然而,有证据表明,这种算法不能由人脑在生物学上实现[1]。其中一个主要原因是反向传播需要前向和后向路径中的突触对称。由于突触在大脑中是单向的,前馈和反馈连接在物理上必须是不同的。这就是所谓的重量运输问题。
为了克服这一限制,最近对学习算法的研究通过研究更具生物学意义的算法,专注于神经科学和机器学习之间的交叉。其中一个主要的方法被称为反馈校准,它采用不同的前向和反馈突触权重。
不同学习算法的比较:反向传播、FA 和 DFA——作者图片
除了提供更具生物合理性的训练方案之外,已经表明对齐方法可以提高深度学习模型对抗敌对攻击的鲁棒性。最后,对反馈对准的额外兴趣还受到它们允许前向和反馈权重在专用集成电路(ASICs)中本地存在的能力的驱动,这最终允许节省时间和能量。
在这篇文章中,我将描述主要的反馈校准方法,并展示一个比较它们的准确性和鲁棒性与反向传播的基准。
反馈校准方法介绍
反向传播在生物学上是不合理的
使用反向传播的 N 层神经网络的训练在前向传递和后向传递之间交替,前向传递用于执行推理和计算误差信号,后向传递用于发送误差信号和更新权重。
我们可以观察下面的权重更新规则:
反向传播权重更新规则
层 i 的权重更新需要前向权重矩阵 W_(i+1)的知识。那个在生物学上是不可信的,因为它要求神经元互相发送大量的突触权重来执行反向传递。
重量运输问题——图片由伊恩·泰勒在 Unsplash 上拍摄
反馈校准算法避免了重量转移问题
反馈对准算法提出在后向传递中替换前向权重矩阵 W 信息,消除了传输权重的需要。不同方法之间的差异包括如何计算后向传递以及如何构建后向权重矩阵 B 。
反馈校准(FA): 权重更新的计算方式与反向传播相同,但反向权重矩阵是随机矩阵[2]。将 B 初始化为与 W 具有相同的分布和数量级有助于提高网络训练的收敛性。下面的公式描述了 FA 的权重更新规则:
一致符号一致反馈(uSF): 这种权重更新方法类似于 FA,但是它通过假设单位幅度的突触权重来传输前向矩阵的符号[3]。因此, B 矩阵为:
分批随机幅度符号一致反馈(brSF): 该方法不是为第 i 层的后向权重假设一个单位幅度,而是在每次更新后重新绘制它们的幅度|R _ I|,使得:
固定随机幅度符号一致反馈(frSF): 这是 brSF 方法的变体,其中权重的幅度|R _ I|不是在每次更新后重新绘制,而是在训练开始时固定和初始化。
直接反馈校准(DFA) :虽然 FA 中的权重更新是跨层递归计算的,但是可以通过直接将最后一层的损耗导数 𝛿z_N 向后推至所有层来预测误差传播【4】。这将导致以下更新:
其中 B_i 是一个适当形状的固定随机矩阵(即 layer_i 的输入维数×layer _ N的输出维数)。
算法基准
在本节中,我将解释在反馈校准算法【5】的准确性和鲁棒性基准测试中进行的实验。我们使用了 BioTorch 开源框架来进行基准测试。
我们使用 Xavier uniform 初始化我们的层的前向和后向权重,W 和 T2。使用这种方差保持初始化允许我们将权重保持在相同的数量级,并且改进了不对称条件下的训练。对于 uSF 方法,我们通过 Xavier 初始化的标准偏差来缩放权重的符号。
我们的实验表明,根据优化器的选择,模型的分类准确性存在显著差异,特别是对于 FA 和 DFA,即使在调整了它们各自的学习速率之后。为此,我们展示了 SGD 和 Adam 优化器的实验结果。
MNIST &时尚 MNIST
我们通过在 MNIST 和时尚 MNIST 数据集上对 LeNet 的所有对齐方法进行基准测试来开始我们的实证研究。用设置动量为 0.9 的 SGD 优化器和 10^(−3).的权重衰减来训练网络我们训练了 100 个时期,在第 50 个和第 75 个时期将初始学习率降低了 2 倍。
MNIST 和时尚 MNIST LeNET 网络的最大错误率(%)
我们观察到 FA 和 DFA 的性能接近 BP,并且符号一致性方法在 MNIST 上匹配 BP 性能。如果我们增加数据集的难度(时尚 MNIST),反向传播和其他方法之间的性能差距,特别是那些不使用符号一致反馈的方法,也会增加。
CIFAR-10
为了将对齐方法的应用扩展到更深层次的架构和更具挑战性的任务,我们在 CIFAR-10 中对 ResNet-20 和 ResNet-56 进行了基准测试。使用 SGD 优化器的网络以 0.9 的动量和 10^(−4 的权重衰减来训练)。使用 Adam 的网络用相同的权重衰减和等于[0.9,0.999]的 betas 参数来训练。我们以 128 的批量进行 250 个时期的训练,在第 100、150 和 200 个时期将初始学习率降低 10 倍。我们使用网格搜索来选择每种方法的最佳学习率。
在 FA 和 DFA 方法的两种网络配置中,Adam 使用的自适应参数独立优化器都优于 SGD,如下所示。这些方法是反向通道中的不对称性较大的方法。
使用 SGD 和 Adam 训练的每个方法的 ResNet-20 和 ResNet-56 的 CIFAR-10 中的前 1 名错误(%)
Adam 带来的显著改进是可以预期的,因为它保持了基于从 RMSProp 继承的梯度的二阶矩的平均值而调整的每个参数的学习率。因此,它在噪声梯度下产生更好的性能。为了证实这一观察,我们为 SGD 和 Adam 优化器绘制了 DFA 方法的后向-前向范数权重比。
在 CIFAR-10 上为 SGD 和 Adam 训练 ResNet56 时,方法 FA 和 DFA 的权重比
可以观察到,SGD 已经驱动网络的第一层的范数权重比非常接近 0,这意味着前向权重矩阵 W_i 被更新以达到比后向权重矩阵 B_i 中的值大得多的值。这是由于在 DFA 方法中误差从最后一层到每一层的直接误差投影,从而避开了使用链规则计算的梯度的小范数。
同样的观察结果不适用于 FA 方法,其中第一层的权重范数比不为零,如下所示。然而,我们看到,与 SGD 相比,Adam 实现了更小的前后重量排列角度。
用带 SGD (a)和 Adam (b)的 FA 训练的 ResNet-20 的矩阵排列(左)和重量比(右)
ImageNet
最后,我们在 ImageNet 上对所有训练 ResNet-18 网络的方法进行了基准测试。我们使用 256 的批量大小,并使用初始学习率为 0.1 的 SGD 训练 75 个时期。调度器在第 20、40 和 60 个时期将学习速率降低 10 倍。我们使用 10^(−4 的重量衰减)和 0.9 的动量。对于 DFA,我们使用初始学习率为 0.001 的 Adam。我们的结果可以在下图中看到:
用所有反馈校准方法训练的 ResNet-18 网络的前 1 名 ImageNet 验证误差(%)
我们可以观察到,就性能而言,没有一种比对方法可以与反向传播相比。虽然符号一致反馈方法在精度上更接近,但是仍然有小的差距。对于 FA 和 DFA 方法,差距要大得多,这意味着在训练过程中反馈权重不能与反向权重对齐。
结论
反馈比对算法是一种比反向传播更具生物合理性的替代方法,因为它们避免了重量转移问题。在整个基准测试中,我们已经看到,尽管它们的性能与 MNIST 和 CIFAR-10 相当,但它们无法扩展到 ImageNet 之类的困难任务。然而,在使用 ASICs 的应用中,它们的应用可以有助于降低成本,因为反馈和反向权重是独立的。此外,这些方法的研究仍然很重要,因为在神经科学的帮助下,有助于我们揭示和了解更多关于人类大脑学习过程的信息。
感谢阅读,希望你喜欢这篇文章,并学到一些新东西!
参考
[1]蒂莫西·P·莉莉卡普、亚当·桑托罗、卢克·马里斯、科林·J·阿克曼和杰弗里·辛顿,反向传播和大脑 (2020 年),《自然评论神经科学》。
[2] Timothy P Lillicrap,Daniel Cownden,Douglas B Tweed 和 Colin J Akerman,随机突触反馈权重支持深度学习的误差反向传播 (2016),自然通讯。
[3]李倩·廖、乔尔·雷博和托马索·波吉奥,权重对称在反向传播中有多重要? (2016),《AAAI 人工智能会议论文集》。
[4]Arild nkland,直接反馈对齐提供深度神经网络中的学习 (2016),神经信息处理系统。
[5] Sanfiz,Albert Jiménez 和 Mohamed Akrout,对反馈对齐算法的准确性和鲁棒性进行基准测试 (2021), arXiv 预印本 arXiv:2108.13446 。
脸书人工智能反馈变压器
解决具有反馈记忆的变压器的一些限制
保罗·库科在 Unsplash 上的照片
在自然语言处理时代,Transformer 架构的增强已经成为革命的核心,突破正以前所未有的速度发生。本文展示了反馈变换器的概念,它克服了传统变换器架构以及递归神经网络的缺点,使较浅的模型具有更快的解码速度、更少的内存以及所需的计算,最重要的是,可以利用来自所有先前层的所有计算信息,而不像仅解码变换器那样为了并行训练而牺牲很多信息。
在进入反馈存储器的杂草之前,让我们修改变压器架构!
自然语言处理中的转换器架构旨在解决序列到序列的任务,同时轻松处理长范围依赖。这个模型完全依靠对 自我关注 来计算其输入和输出的表示,而不使用序列对齐的 RNNs 或卷积。
让我们在此一窥其架构,更深层次地钻研其推荐访问论文 关注你所需要的 !
图 1:变压器架构综合视图
RNNs 和变压器架构的局限性
在 RNN 和变压器架构的情况下,不是所有计算的信息都被使用,尽管在技术上,人们可以利用它,但是为了并行训练,做出了牺牲。然而,新颖的反馈变换器架构使用具有相对更强性能的浅层模型来揭示从所有先前表示到所有未来表示的信息。
递归神经网络及其局限性
图 2:对 RNN 建筑及其缺点的直观研究
在 RNN 的情况下,所有信息仅在顶部和右侧方向流动,因此有大量信息丢失。此外,为了与其他信息相结合,这些信息通常需要经过多次计算。
变压器及其局限性
Transformer 体系结构有许多局限性,例如它不能有效跟踪长序列以及处理分层输入。这种架构的一些最重要的限制是:
(A)对更高级别陈述的有限访问
(B)如果频繁更新,变压器无法长时间保持内部状态
图 3:变压器及其缺点的直观研究
引入带反馈存储器的变压器
为了克服变压器结构的局限性,引入了反馈记忆的概念。正如我们可以在图 3 中分析的,每个隐藏的表示都有许多箭头(即连接),这种数量的注意力连接可以引爆任何系统。为了克服这一点,反馈记忆将特定时间步长的所有信息混合到一个记忆表示中。随后的层不再关注先前层的单独表示,现在只关注单一的记忆表示。
图 4:(左)反馈转换器将所有层的隐藏表示合并成一个向量,并存储在内存中。(右)反馈和变压器的区别。t 表示时间步长,l 表示层。
将信息存储到相应的存储器表示中的显著好处在于使用了总体更少的存储器以及更少的计算,因为这种方法共享了注意机制的密钥和值计算,从而由于存储器共享而进一步导致 GPU 存储器使用的减少。
图 5:解释变压器和反馈变压器中下一层表示的计算差异
反馈变压器架构的优势
以下是将反馈存储器引入变压器架构对性能提升的主要贡献:
- 能够用小而浅的模型实现更好的性能
图 6:wmt 14 En-De 上的机器翻译,测试集 BLEU 和不同解码器深度的解码速度(每秒字数)。
根据图 6 的检查结果,可以得出结论,随着解码速度的提高,由于较浅的网络,即架构中的层数较少,与反馈变压器相比,变压器的性能下降更多。
2。与变形金刚 相比,反馈变形金刚收敛以在强化学习中达到更高的平均回报
图 Gridworld 中的迷宫导航。显示反馈变压器与标准变压器的平均奖励比较。
强化学习任务通常需要长时间的记忆来最佳地解决任务。从图 7 可以诊断出,与变压器架构相比,反馈变压器收敛以在任何训练步骤达到更高的回报。
结论
尽管在训练和推理时间期间使用了相当少的存储器,但是与具有更小和更浅模型的相同大小的变换器架构相比,反馈变换器以更快的解码速度实现了更强的性能。保留远程信息流以及立即访问可用的更高表示信息是具有反馈记忆的变压器的一些主要贡献。
参考资料:
[1]范,安吉拉,等,“解决变压器的一些限制与反馈记忆。”arXiv 预印本 arXiv:2002.09402 (2020)。
[2]瓦斯瓦尼、阿希什等人,“你所需要的只是关注。” arXiv 预印本 arXiv:1706.03762 (2017)。
希望你能像我写这篇文章一样喜欢阅读这篇文章!
如果你觉得这些内容有意义,可以看看我的其他文章 这里 。
喂野兽:深度学习训练的数据加载路径
通过了解和调整从磁盘到 GPU 内存的数据加载,优化您的深度学习培训流程
大卫·拉扎罗在 Unsplash 上拍摄的照片
深度学习实验速度对于按时交付高质量的解决方案非常重要。
数据加载路径——即将训练样本从存储中获取到 GPU 中是一个经常被忽视的领域,尽管它对实验速度有着重大影响。
在这篇文章中,我将介绍数据加载路径的组件,如何形式化它们的性能目标,以及如何设计满足这些性能目标的解决方案。
逆向工作—从 GPU 到存储
基本原理—让 GPU 保持忙碌
购买/租赁 GPU 非常昂贵。因此,在培训期间,您希望确保他们处于 100%的利用率,处理这些矩阵并更新权重。
GPU 在小批量中的工作效率最高,即通过将网络运算符表示为多维张量,同时将它们应用于大量训练示例。从纯计算效率的角度来看,批量越大越好(主要限制是 GPU 内存)
为了保持 GPU 的高利用率,我们需要确保在小批量(向前+向后传递)的训练步骤结束时,下一个小批量将准备好传输到 GPU 的内存中。
GPU 利用率下降表明数据加载太慢。作者图片
数据加载性能要求(针对单个 GPU)
定义:
n =小批量
t=小批量 GPU 处理时间
在典型的训练制度中,这些值在整个训练过程中是固定的。
目标:
99%的小批量应在秒或更短时间内加载 n 个实例。
简单测量的上限可以是:
- 最大延迟 (单例)≤ t
- 最小吞吐量 (例/秒)≥n/t**
什么影响 n 和 t?
首先也是最重要的, n 是一个超参数,你需要调优它,让你的网络真正收敛,学习你希望它学习的东西。
通常,如果训练数据量很小,您会选择较小的批量(例如 16/32),如果训练数据量很大,则选择较大的值。
选择正确的批量大小可以使网络更快地收敛。作者图片
t 是 GPU 需要在小批量上执行的计算量(FLOPs)** 的函数;这取决于 GPU 型号、网络复杂性和 n.**
最后, n 受到可用 GPU 内存数量的限制。存储器需要保存整个小批量的网络状态。
网络状态的内存占用随着批处理的大小而线性增长,因为它包含反向传播所需的每个训练示例的激活和功能
迷茫?让我们看一些例子。
Resnet 50 上的 Imagenet
Resnet 架构。来源:kaggle.com
- 数据表示— 224X224X3,双精度(32 位)
- 单个示例的计算— 4 GFLOPs (约 40 亿次浮点运算)
- GPU 型号— V100,16 GB。能够进行 7 TFLOPS (每秒约 7 万亿次浮点运算)****
- GPU 内存中单个示例状态的大小:103 MB
- 内存中模型参数的大小:98MB(约 2500 万个可训练参数)
分析:
- V100 应该能够每秒处理 7 TFLOPs。
结果应该是每秒处理 7 TFLOPS/4GFLOPs = 1750 个实例
注:NVIDIA 公布的数字是 1457 ,可能是由于从 CPU 获取实例到 GPU 内存的开销。 - 内存大小为n128 = 103 mbx 128+98MB = 12.97 GB。
这意味着 n =256 不适合 GPU 内存。** - 结果: n=128,t = 128/1457 = 0.087s
接下来,为了在带有 Resnet 50 网络的 V100 上训练 imagenet,我们要求我们的数据加载为我们提供以下内容:
t =单个图像的最大延迟≤87 毫秒
n/t =每秒约 1457 张图像的读取吞吐量
rest net 152 上的 Imagenet
为了让您了解改变网络架构对性能的影响,下面是用 Resnet 152 重复的相同实验:
- 内存中单个示例的大小:219 MB(是 Resnet 50 的两倍)
- 内存中模型参数的大小:209 MB(约 5000 万个可训练参数)
- 单个示例处理成本= 8 GFLOPs
- n= 64(64 * 219 MB = 13.8 GB)
- t = 0.087s(总计~每批计算量相同)
t =单个图像的最大延迟≤87 毫秒
n/t =每秒约 730 张图像的读取吞吐量
因此,一个“小”的架构变化会导致数据加载性能需求的巨大变化。
猜测数据加载需求的经验法则
小数据
为了充分利用每个训练示例,您需要较小的 n 值。
在这种情况下:
- t 会很短(几十毫秒)
- n 会小(如 16/32)
- 吞吐量( n/t )仍然可以很高
大数据
**如果您有大量数据,您通常会使用容量更大的网络,并针对更多时期对其进行训练。这种情况下,你要一个大 n 。你的网络可以接受而不会混淆,再加上,否则,训练将永远进行下去。
当你想要一个高 n 的时候,你面临着一个问题 GPU 内存中每个例子的大小都会很大(高复杂度网络)——这就限制了 n (并延长了 t )。****
为了解决这个问题,常见的解决方案是:
- 使用分布式训练,使用多个 GPU(同一台机器/集群)处理整个大批量
- 减少网络的内存占用(例如混合精度)
因此:
- t 可以相对放松(比如说 2 秒)
- n 可以很大(比如说 1024)
分解数据加载过程
由于 GPU 本身必须忙于学习,一个显而易见的选择是使用 CPU 加载和准备数据——CPU 反正连接到每台机器,除此之外几乎没有任何事情可做。
当前一批正在 GPU 上处理时,使用 CPU 工作线程加载小批。作者图片
为 GPU 准备小批量包括以下步骤:
- 决定需要加载哪些示例(通常使用数据集的混排)
- 从存储(IO)加载示例
- 转换,如预处理或扩充(CPU)
- 将它们存储在 RAM (CPU)中
- 将张量传输到 GPU 内存(CPU)
使用并行性实现吞吐量 大量的 I/O、每个示例的中高延迟以及拥有许多空闲内核的强大机器表明,在数据加载中使用并行性是明智的。
为了进一步卸载并降低对延迟峰值的敏感性,如果我们有空闲的工作人员,就有机会急切地从下一个批次的中加载示例(确保不要破坏 RAM……)**
我们现在将更深入地研究数据加载的主要部分,从 CPU 对示例的处理向后追溯到从存储中读取数据的实际 IO。
在这篇文章中,我们不会讨论将数据从 RAM 移动到 GPU (5)的步骤,尽管这也很重要,并且有多种优化,如 PCIe、NVLink、固定内存等。
阶段 3 —从原始输入示例到训练示例
GPU 期望为它的小批量接收张量。
然而,通常我们从存储器中加载的不是张量,而是数据的其他二进制表示,例如. jpg 文件。
在简单的情况下,将原始输入示例转换为定型示例就像将. jpg 解码为像素一样简单。在其他情况下,我们会进行各种变换(例如下采样)和增强。
转换甚至可以包括原始输入示例和训练示例之间的多对多关系。天空是极限,但当然,所有这些都花费了我们在 CPU 上的时间。
还有一个需要考虑的内存占用,特别是如果您不能在数据仍处于压缩形式时对其进行缩减采样,但我们现在将把这个问题放在一边。
来源:相册项目(麻省理工学院许可)
如果您的处理量很大,您可以通过提前批量处理,并将处理过的示例存储在磁盘上来进行优化,从而减少 CPU,甚至减少磁盘上的文件大小。
阶段 2 —从存储中加载示例
在大多数情况下,I/O 是数据加载的最大成本。
一般情况下我们需要注意的存储参数有:
- 以 GB 为单位的存储总大小=基于我们的训练集大小
- 读取 IOPS = n/t(假设 CPU 处理时间可以忽略不计)
- 块大小(=磁盘上的典型示例大小,以 MB 为单位,表示为 es)
- 读取带宽(MB/s) = es * n/t
注意:如果我们考虑使用共享存储进行多个并发实验:
- 对于训练数据的总大小(以 GB 为单位)-对您计划训练的所有数据集使用联合
- 从您计划的训练负荷中选择一个具有挑战性的组合 t,n,es
- *使用 n = #并发实验 典型批量
示例——四个 v100 训练图像网络和 Resnet 50
- 总数据集大小 = ~150 GB
- n = 1284 = 512*
- t = 0.087
- es = 469x387 像素 jpg,说 64 KB 。
结果:
- IOPS = 512/0.087 = 5885
- 块大小 = 64 KB
- 读取带宽 = 367 MB/s
这些要求适合现代 SSD 存储设备。
为了在旋转的磁盘上实现类似的性能,我们需要同时将负载分散到大约 45 个磁盘上。
现代旋转磁盘的 IOPS 和块大小。来源:wikipedia.com
当你是一名研究人员,在几十 GB 的稳定数据集上训练网络时,本地 SSD 驱动器是你的朋友。它们并不昂贵,您可以在合理的时间内获得它们的数据,并且您可以获得很好的性能,而无需过多考虑 I/O。
随着您的培训操作扩展存储
当您有一个由 15 名工程师和研究人员组成的团队,在一个训练集群上同时运行数十个实验,并且每月利用数 TB 的训练数据时,会发生什么?
在训练之前将数据集复制到连接的存储设备(例如本地磁盘或块设备)实际上不是一个选项。
- 要么是数据太大,要么是复制时间太长
- 如果您在集群上进行培训,您需要能够轻松地“移动”机器,而使用附加存储则无法做到这一点。
较大的 DL 培训操作需要远程存储解决方案,该解决方案通过使用来自培训机器的 API 来“安装”或访问。
典型的解决方案包括结合 HDD 和 SSD 的横向扩展 NAS 存储。这些解决方案以高吞吐量提供并行读取,并且在许多情况下,延迟是可接受的。
体面的 NFS 可以处理更大的文件和宽松的延迟
让我们来看看一个理论上的 DL 商店的储物需求:
- 5tb 到 10 TB 的数据(仅活动使用的数据)
- 5-10 个同时进行的实验
- 每个实验的 GPU 数量= 4
- n = 单个 GPU= 64
- es = 500K
- t = 2s(重网)
这将需要:
- IOPS—640–1280
- 读取带宽 — 600 MB/s — 1.28 GB/s
小输入/短延迟是一个代价高昂的问题
存储有一个众所周知的问题,叫做“小文件问题”。本质上,这意味着进行快速随机访问和返回小块是昂贵的。
这里有一个例子:
- 5tb 到 10 TB 的数据(仅活动使用的数据)
- 5-10 个同时进行的实验
- 每个实验的 GPU 数量= 4
- n = 单个 GPU= 256
- es=64K**
- t= 0.2s
这将需要:
- IOPS = 25600–51200
- 读取带宽= 1.6–3.2 GB/秒
在标准 NFS 解决方案中,非常快速地加载许多小文件是有问题的——您要么需要将数据分布在大量驱动器上,要么使用昂贵的 SSD 阵列和其他高端解决方案
了解工作负载特征
从存储的角度来看,用于培训的数据加载有一组非常独特的特征:
- 单个“原始输入示例”的大小可能会因数据的形态而有很大的不同,从每个原始输入示例几十 K 到几 MB 不等。
- 数据被“批量”读取、处理和写入,然后被多次读取
- 对于延迟峰值,读取稍微宽松一些,更关心吞吐量
- 数据是“随机”访问的,因为小批量会打乱每个小批量中包含的示例
- 一旦读取了单个数据示例数据,几乎可以保证它会在相对较短的时间框架(每个时期)内被反复读取
这些可以用来以创造性的方式优化存储。
利用负载特征优化存储
要优化存储解决方案,请考虑使用以下部分或全部方法:
首先-使用紧凑的表示格式,这将尽可能减小单个示例的大小。如果数据将在一秒钟后被向下采样,则不需要支持高带宽!
第二,您可以使用本地的部分缓存解决方案(例如 SSD),利用未来时代的缓存命中保证。如果您能够以这种方式随机缓存 20%的数据集(惰性),那么您可以轻松获得加速。
最后—尝试从非常短的延迟/许多随机 IOPS 转向更长的延迟和顺序读取。
坦率地说,应该避免上面讨论的极端情况(非常短的延迟,许多小的随机 IOPS)—例如,通过使用较弱的 GPU,或者通过在不同的培训工作之间共享 GPU。
但是,即使对于更温和的情况——如果我们可以在磁盘上批量处理例子,会怎么样呢?我们将依次读取 1 个较大的文件,而不是读取个小文件并进行多次寻道?**
这是一个吸引人的想法;挑战在于支持每个时期的随机洗牌——但事实证明,如果你足够努力,这是可以解决的…
在不久的将来,我会试着在另一篇文章中讨论这些问题。
摘要
保持 GPU 的充分利用需要了解和优化数据加载路径-从磁盘到 GPU 内存。
这样做的细节取决于各种参数,如数据的大小,以及您拥有的计算资源和您正在训练的网络。
在这篇文章中,我试图介绍数据加载流程和优化的基础知识,并提供一些解决方案。
请继续关注下一期文章,它将关注存储优化技术。
感到沮丧和不知所措?管理数据科学中具有挑战性的学习过程的九个技巧
数据科学讨论
根据我的个人经验,我提出了九个策略来开始在数据科学的广阔世界中前进,而不会被它所压制。
克里斯托夫·奥特在 Unsplash 上拍摄的照片
正如我们所知,数据科学家的工作需要很多技能,包括统计和数学概念、可视化技能和编程知识。对于一个初学者来说,所有这些要求都可能是一个障碍。事实上,人们可能会想甚至没有迈出第一步就离开。
在这篇文章中,我描述了我的经历,以及我是如何开始在数据科学的巨大丛林中迈出第一步的。基本上,通过遵循九个简单的步骤,并有很大的耐心,你可以成为一名(好的)数据科学家。
乌代·米塔尔在 Unsplash 上拍摄的照片
在开始数据科学家的旅程之前
在我们进入数据科学的世界,然后将我将描述的技巧付诸实践之前,还有一场更大的战斗要打。
第一场真正的战斗是对抗焦虑。是的,因为有太多的工作要做,你可能会认为你必须马上以最好的方式做每一件事。
事实上,这是我对数据科学的第一次影响:我想知道如何做每件事,甚至在开始之前。
在开展数据科学家的工作时,我个人对以下情况感到焦虑:
- 数据集太复杂而无法分析 —尽管应用了许多预处理技术等,但数据集仍然庞大而复杂;
- 一个训练时间太长的机器学习算法——等待结果让人伤脑筋;
- 即将到来的截止日期和仍然部分的结果;
- 一段不工作的代码——花费数小时试图让代码工作或找到一个问题的解决方案令人沮丧,可悲的是没有成功;
- 要学习的概念太多(尤其是关于统计和数学),而学习的时间太少。
如果你在其他情况下经历过开始数据科学家之旅时的焦虑, 欢迎评论本文 。我很乐意用其他焦虑情况来更新之前的列表。
照片由 Francesco Dondi 在 Unsplash 上拍摄
九大秘诀
然后我就想,这种情况不能再继续下去了。我停下来思考了一下,最终我总结出了九条建议,并付诸实践,开始了数据科学家的旅程。
1 保持冷静!
开始学习过程的第一个方法是保持冷静。理论上这似乎是显而易见的,但实际上,也许这是最难应用的东西。
保持冷静是强者的美德。它需要强大的自制力,无尽的耐心和极大的节制。
保持冷静的关键,比如在学习一个复杂的统计概念之前,就是从情境中退出。只考虑现在,想象你的一生都在学习。
Ravi Pinisetti 在 Unsplash 上拍摄的照片
2 阅读和学习
成为一名优秀的数据科学家的另一个重要方面是对所涉及的主题有很好的了解。确定如何进行数据清理、分析等的唯一方法。,就是学习。
没有别的选择:我必须学习。
我不能不先发动引擎就开车离开。数据科学家的工作也是如此。如果我首先没有一些理论知识,我是无法训练出一个模型的。
学习技巧可以有所不同:你可以拿一本手册来学习,你可以阅读关于它的文章等等。就我个人而言,我更喜欢阅读有趣的文章和测试示例,因为只有通过实践才能学到东西。
从我的经验来看,在一门学科的知识上取得进步的唯一方法是留出时间来学习,不管是每天一小时还是每周一小时。重要的是这个时间是存在的。当然,花在学习上的时间不是浪费时间,相反,它有助于快速进步。
照片由 Aaron Burden 在 Unsplash
3 寻求帮助
在电脑上工作时,我们经常忘记我们并不孤单。很多时候我花了很多时间在谷歌上搜索解决方案,有时成功,有时不成功。
事实上,其他人可能已经准备好了解决问题的方法,这对我们来说似乎是不可克服的。
随着时间的推移,我了解到有许多数据科学家社区,他们非常愿意在困难的时候帮助我。
例如,在 Quora 、 Stackoverflow 、 Reddit 、 Linkedin 以及所有社交网络上都有数据科学社区。随便问!
照片由 Hannah Busing 在 Unsplash 上拍摄
4 组织工作
为了消除焦虑,另一个基本要素是工作的组织。
随着时间的推移,我明白了一张纸比云上的一千份文件更有价值,因为它能让我接触(并用眼睛聚焦)所有要做的事情。
基本上,我拿了一本旧日记,开始逐月记下所有要做的事情。我认为每一项数据科学任务都是需要做和学习的事情。我用黄色突出显示了每个已完成的任务。看到日记渐渐变黄,多么令人满意!
由于有了议程,我对各种主题的知识逐渐增加,因为一切都在掌控之中,组织今天和明天要做的工作变得更容易了。
测量我的力量
经常被做这么多事情的热情淹没,开始了太多的数据科学活动或项目,最终陷入了不成功的焦虑。
从这些经历中,我学会了衡量自己的力量,在工作量和我实际能做的事情以及我可用的时间之间找到平衡。
这与是否具备启动新数据科学项目或新业务的技能无关。相反,这是一个衡量自己实力的问题,以避免仓促行事和重新陷入失败。
不要对自己期望太高
与上一点密切相关的是不要对自己期望过高。说实话,我有时发现自己对自己的要求超出了我当时所能给予的。
生活中有些时候你表现得更好,有些时候你进展得更慢。重要的是永远不要停下来。尽管如此,即使一会儿,你走得更慢。
例如,如果我的技能没有超越 Excel,我就不能期望做出漂亮的 Mike Bostock 可视化!
7 优化时间
数据科学家职业生涯的另一个重要步骤是优化时间。数据科学家工作流程中的一些任务需要很长时间,例如训练模型。在这种情况下,不建议每五分钟检查一次任务是否完成。在等待的过程中,我决定用不同的方式来安排时间,正如我在这篇题为如何在等待数据分析输出的时候度过时间的文章中所解释的那样。
另外,我意识到有多种技术可以加速代码,这样所有操作都加快了速度。在这篇文章中,我描述了三个技巧来加速和优化你的 python。
8 休息一下
在某些情况下,避免沮丧的最简单方法就是休息一下。
一杯咖啡、一次散步或深呼吸可以帮助你从另一个角度看待现实。
在很多情况下,我发现自己解决问题的方法只是想一会儿别的事情,然后带着清晰的头脑回到这个问题上。以我的经验来看,获得一段不起作用的代码的最好方法是拔掉电源插头一会儿,从电脑前站起来,哪怕只是看看窗外。回到电脑前,问题突然变小了,挫败感消失了,问题也消失了。
9 接受现实的本来面目
如果真的无法开始数据科学家的职业生涯怎么办??还有最后一次机会。这是关于接受现实。
我什么意思?我举个例子。
让我们想象一下,我们试图研究机器学习算法背后的概念,却什么也没有理解。我们再想象一下,你努力学习 Python,却连 Hello World 这句话都不会写!
好吧,有什么办法呢?绝望?肯定不是。不值得。
我将尝试关注数据科学的另一个方面,可能是数据可视化和数据收集。数据科学如此广阔,每个人都有适合自己的东西。
找不到任何适合自己的数据科学领域怎么办?我知道这不是适合我的职业,最好去找其他的职业。
托拜厄斯·比约克内斯在 Unsplash 上的照片
摘要
在本文中,我分享了我的个人经验,即管理数据科学中具有挑战性的学习过程的九个技巧。
如果你在阅读方面已经走了这么远,这意味着你有时也会考虑放弃数据科学家的职业。我希望通过实践这九个技巧,你也能成为一名优秀的数据科学家。
如果你想分享你的经验,欢迎在评论中写下。我很乐意回答你!
如果你已经走了这么远来阅读,对我来说今天已经很多了。谢谢!你可以在这篇文章中读到更多关于我的信息。
你愿意支持我的研究吗?
你可以每月订阅几美元,解锁无限的文章——点击这里。
相关文章
https://medium.com/geekculture/is-the-semantic-web-really-dead-7113cfd1f573
一个额外的提示
实际上,还有最后一个,也是第十个建议,我可以建议你付诸实践,开始你的数据科学家之旅:
既然你不可能知道所有的事情,那么最好的办法就是对数据科学这个广阔的领域有一个大概的了解,但是然后只关注一个很小的领域。
从托莱多的 OSM 数据中提取绿色区域
如何使用 OSMnx 以几何图形的形式检索公园
图片由作者提供。OSM 数据托莱多市中心(建筑、道路、公园)
我在赫尔辛基大学的自动化 GIS 课程中担任研究助理的经历非常棒。我支持学生的任务,提供 GIS 流程自动化方面的提示。我很高兴看到地理学家是如何用 python 脚本接管地理空间分析的。这些课结束了,但学到的东西还在。我想保留的一个类是由 Geoff Boeing 创建的 python 库 OSMnx 的用法。多亏了这个图书馆,从世界各地的城市获取街道网络成为可能。此外,还可以获取其他元素,如本编码实践所示。我在这里展示了一个关于如何绘制绿色区域和街道网络的简短教程。
如果你有兴趣从 OSM 找到更多的几何物体,你可以仔细查看 OSM 维基上的建筑标签。您可以使用标签来检索咖啡馆、市场、停车场等。另一个有用的网站是 OSM 域名,在那里你可以找到你想要从 OSMnx 中检索数据的地方的名称。因此,不要怀疑测试它与您想要的城市,不要忘记分享您的地图。我会很高兴看到你的作品。我在这种情况下是托莱多。
找到此回购中的材料:获取 OSM
编码实践
首先,您将导入库
**import** osmnx **as** ox
**import** matplotlib.pyplot **as** plt
然后你从 OSM 命名中指定位置并想象这个区域。
**# Specify the name that is used to seach for the data**
place_name = “ Toledo, Castile-La Mancha, Spain”**# Fetch OSM street network from the location**
graph = ox.graph_from_place(place_name)**# Plot the streets**
fig, ax = ox.plot_graph(graph)
由作者想象。托莱多的曲线图
将边(街道网络)放入地理数据框架
**# Retrieve nodes and edges**
nodes, edges = ox.graph_to_gdfs(graph)
将地名(Toledo)放入地理数据框架
**# Get place boundary related to the place name as a geodataframe**
area = ox.geocode_to_gdf(place_name)area.plot();
图片由作者提供。托莱多行政单位
获取带有标签和地名的建筑物几何图形作为地理数据框
**# List key-value pairs for tags**
tags = {‘building’: True}buildings = ox.geometries_from_place(place_name, tags)
绿色区域/公园的标签很棘手,但希望你能在 OSM 维基中找到你需要的所有对象。现在,让我们把绿色区域作为地理数据框架
**# List key-value pairs for tags**
tags = {‘leisure’: ‘park’, ‘landuse’: ‘grass’}**# Get the data**
parks = ox.geometries_from_place(place_name, tags)parks.plot(color="green");
现在我们一起来出图。在整个地区。
fig, ax = plt.subplots(figsize=(12,8))**# Plot the footprint**
area.plot(ax=ax, facecolor=’black’, zorder=0)**# Plot street edges**
edges.plot(ax=ax, linewidth=0.5, edgecolor=’dimgray’, zorder=1)**# Plot buildings**
buildings.plot(ax=ax, facecolor=’silver’, alpha=0.7, zorder=2)**# Plot parks
parks.plot(ax=ax, color=’green’, alpha=0.7, markersize=10, zorder=3)**plt.tight_layout()
plt.axis(‘off’)
图片由作者提供。获取 OSM 数据的托莱多
由于我们注意到区域太大,所以我们将 xlim 和 ylim 指定到市中心,以便以更好的方式可视化 OSM 数据。只需在此之前添加到单元格的末尾
plt.xlim((-4.05, -4.01))
plt.ylim((39.89, 39.85))
图片由作者提供。获取 OSM 数据的托莱多市中心
您可以保存地理数据框,并根据自己的喜好和设计创建地图。主要有:edges
、area
、parks
和buildings
结论
OSMnx 确实可以方便地获取街道网络。它的特别之处在于,您可以在分析中包含大量的几何对象选项。像医院、公园、市场、咖啡馆、餐馆或不同种类的建筑。OSM 维基会给你线索。我希望这是有用的。学习好;)
使用 Python 获取手机号码详细信息
使用电话号码检索手机号码详情
Python 是一种非常丰富的语言,因为它提供了大量的库。它包含多种功能,有助于解决现实生活中的业务问题。今天我们将讨论这样一个库。
Phonenumbers 是一个开源 Python 库,用于访问电话号码的信息。它还有助于验证电话号码、解析电话号码等。
在这篇文章中,我们将探索电话号码及其功能。
让我们开始吧…
安装所需的库
我们将从使用 pip 安装来安装 Phonenumbers 开始。下面给出的命令将使用 pip 安装 Phonenumbers。
pip install phonenumbers
导入所需的库
在这一步中,我们将导入访问电话号码信息所需的所有库。
import phonenumbers
from phonenumbers import carrier, geocoder, timezone
访问关于电话号码的信息
现在,我们将访问我们想要的任何电话号码的信息,我们需要传递国家代码,后跟电话号码,它将显示该号码的详细信息。
mobileNo=input("Mobile no. with country code:")
mobileNo=phonenumbers.parse(mobileNo)
print(timezone.time_zones_for_number(mobileNo))
print(carrier.name_for_number(mobileNo,"en"))
print(geocoder.description_for_number(mobileNo,"en"))
print("Valid Mobile Number:",phonenumbers.is_valid_number(mobileNo))
print("Checking possibility of Number:",phonenumbers.is_possible_number(mobileNo))
信息(来源:作者)
在这里,您可以看到与我们提供的号码相关的信息是如何显示的。同样的,你也可以针对不同的手机号码进行查看。
接下来,让我们看看如何从文本中解析电话号码,以及如何格式化它。下面给出的代码将执行这些操作。
text = "Call me at 1800-202-2022 if it's before 9:30, or on 703-4800500 after 10am."
for match in phonenumbers.PhoneNumberMatcher(text, "US"):
print(match)
x = phonenumbers.parse("+442083661177", None)
phonenumbers.format_number(x, phonenumbers.PhoneNumberFormat.NATIONAL)
解析(来源:作者)
尝试用不同的文本和数字来解析数据和格式化电话号码。您可以在任何实际项目或问题中轻松实现这一点。在回复部分让我知道你对这个库的看法。
本文是与皮尤什·英加尔合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。
Python 中的斐波那契回撤
让我们看看如何用 Python 计算这个强大的技术指标
斐波那契回撤的例子。作者图片
量化交易者总是根据技术指标和高级图表寻找交易机会。交易者寻找的最好的指标之一是价格可能反弹的关键水平。其中一些水平是斐波纳契回撤。让我们看看它们是如何工作的。
什么是斐波那契回撤?
斐波纳契回撤是根据两次摆动计算的特殊关键水平,即反转点。斐波那契回撤背后的想法是根据预先定义的分数,在这两个波动之间的价格范围内创建一些关键水平。最重要的分数是 0.618,与黄金分割比(1.618…)有关。这就是为什么它们被称为斐波那契回撤。其他比值为 0.5,0.236,0.382,0.786。
这里有一个斐波纳契回撤的例子:
斐波那契回撤的例子。图片作者。
第一秋千与第二秋千相连。由于第二次摆动高于第一次,因此趋势看涨。然后,从第二次摆动开始,我们根据我们想要使用的分数的需要画尽可能多的水平线。我们只需减去幅度乘以目标分数。如果趋势是看跌的,我们就要加上这样一个分数。第一个摆幅总是与 1 分数相关,第二个摆幅与 0 分数相关。
它们是如何使用的?
因为它们是关键水平,所以它们可以用于,例如,均值回复策略。从上图可以看出,价格已经反弹到 0.618 水平附近。因此,我们的想法是在水平附近寻找反转模式,以便尝试利用反转。
斐波纳契回撤在交易者中非常受欢迎,为了提高回报/风险比,在很宽的时间范围内使用这个工具非常重要。显然,这个工具不能单独使用,但是我们需要建立一个完整的策略,例如,利用多时间框架分析。
现在让我们看看如何使用 Python 计算斐波那契级数。下面的代码可以在我这里的 GitHub 储存库中找到:https://GitHub . com/gianlucamalato/machine learning/blob/master/Fibonacci _ retracements . ipynb
Python 中的示例
我们先安装 yfinance 库
!pip install yfinance
然后,让我们导入将要使用的库。
import yfinance
import pandas as pdimport matplotlib.pyplot as plt
现在,对于这个例子,让我们导入黄金(GLD)从 2020 年 7 月 1 日到 2021 年 3 月 1 日的每日数据。
name = "GLD"ticker = yfinance.Ticker(name)
df = ticker.history(interval="1d",start="2020-07-01",end="2021-03-01")
现在我们要计算最高和最低的摆动。这些波动将通过第二根蜡烛线的指数来识别。
highest_swing = -1
lowest_swing = -1for i in range(1,df.shape[0]-1):
if df['High'][i] > df['High'][i-1] and df['High'][i] > df['High'][i+1] and (highest_swing == -1 or df['High'][i] > df['High'][highest_swing]):
highest_swing = iif df['Low'][i] < df['Low'][i-1] and df['Low'][i] < df['Low'][i+1] and (lowest_swing == -1 or df['Low'][i] < df['Low'][lowest_swing]):
lowest_swing = i
现在让我们创建一个列表,其中包含与要显示的级别和颜色相关的分数。最后,我们可以计算等级本身。
如果最高的振幅紧挨着最低的振幅,我们有一个上升趋势,否则,我们有一个下降趋势。这有助于在正确的方向上绘制标高。
ratios = [0,0.236, 0.382, 0.5 , 0.618, 0.786,1]
colors = ["black","r","g","b","cyan","magenta","yellow"]
levels = []max_level = df['High'][highest_swing]
min_level = df['Low'][lowest_swing]for ratio in ratios:
if highest_swing > lowest_swing: # Uptrend
levels.append(max_level - (max_level-min_level)*ratio)
else: # Downtrend
levels.append(min_level + (max_level-min_level)*ratio)
现在我们有了绘制价格和斐波纳契回撤线图的所有要素。
plt.rcParams['figure.figsize'] = [12, 7]plt.rc('font', size=14)plt.plot(df['Close'])
start_date = df.index[min(highest_swing,lowest_swing)]
end_date = df.index[max(highest_swing,lowest_swing)]
for i in range(len(levels)):plt.hlines(levels[i],start_date, end_date,label="{:.1f}%".format(ratios[i]*100),colors=colors[i], linestyles="dashed")plt.legend()
plt.show()
作者图片
正如我们所看到的,趋势是看跌的(100%水平高于 0%水平),在价格反弹之前,61.8%水平已经被触及两次。
结论
斐波纳契回撤对于量化交易者来说是非常有用的工具。它们很容易阅读和计算,是交易者策略中非常有用的工具。再次强调,首先测试你的策略并引入更多的规则是很重要的,例如,基于多时间段的分析。
Gianluca Malato 是意大利数据科学家和小说作家。他是数据科学、机器学习和数据分析在线学校【YourDataTeacher.com】的创始人。
参考
[1]吉安卢卡·马拉托。风险/回报比:超越神话的真相。https://medium . com/the-trading-scientist/risk-reward-ratio-the-truth-beyond-the-myth-22a 00 c 258 b 83
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
国际足联终极团队机器学习项目
一个端到端的 ML 项目,预测一个球员在国际足联终极队的评级
古列尔莫·巴西尔在 Unsplash 上拍摄的照片
这个项目遵循 ML 顾问 Aurélien Géron 在机器学习端到端指南中概述的原则/步骤。
介绍
什么是机器学习?
机器学习(ML)是人工智能(AI)的一个子集,它使用计算机算法在大型数据集中寻找模式,而无需显式编程。ML 赋予计算机自我学习和改进的能力,以便它能够从数据中产生最佳模型。如今,许多应用程序都使用 ML,例如:
- 产品推荐
- 垃圾邮件检测器
- 恶意软件检测
- 人脸识别
这个项目是关于什么的?
从我记事起,我就一直在玩国际足联的游戏。我喜欢能够作为我最喜欢的足球运动员和球队踢球。虽然现在的游戏因为大部分是付费赢而名声不好,但我仍然发现自己很享受 FIFA 终极团队(FUT)和竞争性多人游戏的战利品。话虽如此,我一直想知道开发者如何决定玩家评级,然后我问自己,“机器也能做到吗?”。电子艺界(EA)的开发团队很可能使用 ML 模型来决定玩家评级,但这并没有阻止我建立自己的模型。这个项目是我试图创建一个 ML 模型,可以预测任何球员的总体评分。
我用 Google Colabs 来完成这个项目。
我们使用的是哪种数据?
我在 Kaggle 上找到了一个关于国际足联比赛的大型数据集。数据集由 FIFA 15 至 FIFA 20 的数据组成。我们将使用数据集中最新的国际足联游戏,即 FIFA 20。数据集可以从 Kaggle 下载。数据集由 18,278 行和 104 列组成。这些列包含诸如玩家姓名、年龄、身高、体重、国籍等特征。因为我们试图预测总体评分,所以我们只需要关注与总体评分相关的特性,但我们稍后会谈到这一点。
如何入门?
1.定义问题
任何 ML 工程师应该做的第一件事就是定义问题。对于这个项目,我们面临的问题是准确预测玩家评分,而不必硬编码算法,因此建立一个可行的 ML 模型应该是我们的最终目标。在 FIFA 20 中,一个球员的总得分是由每个球员属性的得分来定义的,例如速度、射门、传球、运球和许多其他属性。我们试图根据球员的进攻和防守属性来预测整体得分。数据已经带有标记的训练示例,这意味着我们正在处理一个监督学习问题。这也是一个典型的回归任务,因为我们的任务是预测一个值。更具体地说,这是一个多元回归问题,因为模型将使用多个特征来进行预测。
2.选择绩效评估
既然我们已经定义了问题,我们需要选择一个性能度量。我喜欢用均方根误差(RMSE)。这是回归问题的首选性能度量。RMSE 是衡量模型表现好坏的一个标准。它给出了一个系统在预测中有多大误差的概念。RMSE 是关于最佳拟合线的残差(预测误差)的计算。公式如下所示:
为了更多地了解 RMSE 及其运作方式,我推荐阅读这篇文章。
现在我们准备开始编码了!!!
3.导入库
我们需要做的第一件事是导入最常见的数据科学库,如 numpy 、 scipy 和 pandas 。我们还需要导入 matplotlib 和 seaborn 以便我们可以绘制图表来帮助我们可视化数据。
# Common imports
import numpy as np
import pandas as pd
import os
import seaborn as sns
from scipy import stats
import missingno as msno# To plot pretty figures
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import style
sns.set(style='ticks', color_codes=True)
sns.set(style='darkgrid')
import plotly.express as px# Ignore useless warnings (see SciPy issue #5998)import warnings
warnings.filterwarnings(action="ignore", message="^internal gelsd")
warnings.filterwarnings('always')
warnings.filterwarnings('ignore')
4.下载并浏览数据
我将数据集保存到我的 GitHub 存储库中,这样我可以更容易地下载数据集,而不必在我的机器上搜索它。如果数据不断变化,拥有在线下载数据的功能真的很有用。它还省去了必须在多台机器上安装数据集的麻烦。
import urllib.requestDOWNLOAD_ROOT = "https://raw.githubusercontent.com/jpzambranoleon/ML_Projects/master/"TRAIN_PATH = os.path.join("datasets", "players_20")
TRAIN_URL = DOWNLOAD_ROOT + "datasets/players_20.csv"def fetch_train_data(train_url=TRAIN_URL, train_path=TRAIN_PATH):
os.makedirs(train_path, exist_ok=True)
csv_path = os.path.join(train_path, "players_20.csv")
urllib.request.urlretrieve(train_url, csv_path)
fetch_train_data() 函数用于获取数据集。
fetch_train_data()
数据集被下载并保存在文件夹数据集和玩家 _20 下的 Google Colabs 的文件部分。现在剩下要做的就是将数据加载到 pandas 数据框架中。幸运的是,我们可以创建一个函数来返回 pandas DataFrame 对象。
import pandas as pddef load_train_data(train_path=TRAIN_PATH):
csv_path = os.path.join(train_path, "players_20.csv")
return pd.read_csv(csv_path)
我将 load_train_data() 函数调用到 player_data 变量中,将数据帧保存到一个变量中,以使事情变得更简单。DataFrame 的 head() 方法用于查看数据的前五行。
player_data = load_train_data()
player_data.head()
显示前 5 行。
我使用了 shape 方法来返回一个表示数据帧维度的元组。通过使用 shape 方法,我们可以看到数据集中有多少行和列。
player_data.shape**(18278, 104)**
正如我们从元组中看到的,数据集有 18,278 行和 104 列。我们不需要使用所有的列,所以最好截断数据帧,只包含目标列和玩家统计数据列。有 34 个球员统计栏,所以我们需要选择它们。
#player stat features
columns = ['overall','attacking_crossing', 'attacking_finishing', 'attacking_heading_accuracy', 'attacking_short_passing', 'attacking_volleys', 'skill_dribbling', 'skill_curve', 'skill_fk_accuracy', 'skill_long_passing', 'skill_ball_control', 'movement_acceleration', 'movement_sprint_speed', 'movement_agility', 'movement_reactions', 'movement_balance', 'power_shot_power', 'power_jumping', 'power_stamina', 'power_strength', 'power_long_shots', 'mentality_aggression', 'mentality_interceptions', 'mentality_positioning', 'mentality_vision', 'mentality_penalties', 'mentality_composure', 'defending_marking', 'defending_standing_tackle', 'defending_sliding_tackle', 'goalkeeping_diving', 'goalkeeping_handling', 'goalkeeping_kicking', 'goalkeeping_positioning', 'goalkeeping_reflexes']player_df = player_data[columns]player_df.head()
显示新数据框中的前 5 行。
我在新的数据帧上使用了 info() 方法来快速描述数据。
player_df.info()
我们可以从数据中看到,数据帧中有 18,278 个非空值,这意味着我们不必担心丢失值。
为了获得数据的统计描述,我们可以使用 describe() 方法。
player_df.describe()
为了更好的测量,让我们再次使用 shape 方法来查看新数据帧的维度。
player_df.shape**(18278, 35)**
感受数据的另一个好方法是绘制每个数字属性的直方图。要绘制每个属性的直方图,只需在 DataFrame 上调用 hist() 方法。 hist() 方法需要 matplotlib 库。您可以为每个直方图指定仓的数量,也可以指定图形的大小。我选择了 40 个箱子和(27,17)的尺寸,但是这完全取决于你。直方图很有用,因为它们显示了具有给定值范围(x 轴)的实例(y 轴)的数量。
player_df.hist(bins=40, figsize=(27,17))
plt.show()
从图中可以看出,每个直方图的取值范围是 0 到 100。这很好地表明了每个属性都具有相同的比例,这意味着我们不必进行任何要素比例变换。
为了更好地实践,我喜欢完全确定数据中没有丢失的值,所以我使用了 isna()。any() 方法返回关于数据是否有缺失值的 True 或 False 语句。
player_df.isna().any()
正如我们从输出中看到的,每个属性的返回值都是 False,这意味着没有丢失值。我们准备继续!!!
5.将数据分成训练集和测试集
探索完数据后,我们需要做的下一件事是将数据分成训练集和测试集。我们可以自己拆分数据,或者创建一个函数来完成这项工作。幸运的是,Scikit-Learn 有一个很酷的功能,可以将数据集分成训练集和测试集。 train_test_split() 函数可以很容易地将数据拆分成我们需要的集合。我设置 test_size=0.2 ,这样 20%的数据存储在测试集中。另外 80%的数据存储在训练集中。训练集应该有更多的数据,因为它是模型学习的对象。测试集将是我们用来验证模型的集。
from sklearn.model_selection import train_test_splittrain_set, test_set = train_test_split(player_df, test_size=0.2, random_state=42)print("Length of training data:", len(train_set))
print("Length of testing data:", len(test_set))
print("Length of total data:", len(player_df))**Length of training data: 14622
Length of testing data: 3656
Length of total data: 18278**
6.寻找相关性
您可以使用 corr() 方法计算每对属性之间的标准相关系数。查看每个属性之间的所有相关性会占用太多时间,所以让我们只查看每个属性与整体值的相关程度。
fifa_df = train_set.copy()corr_matrix = fifa_df.corr()corr_matrix['overall'].sort_values(ascending=False)
相关系数范围从-1 到 1。当相关系数接近 1 时,说明有很强的正相关性;例如,当运动反应上升时,整体倾向于上升。当相关系数接近-1 时,意味着存在强负相关(即与强正相关相反)。
为了可视化属性之间的相关性,我们可以使用 pandas scatter_matrix() 函数。该函数将每个数值属性与其他数值属性进行对比。让我们来看看前五个有希望的属性,因为有 35 个数字属性。
from pandas.plotting import scatter_matrixattributes = [‘overall’, ‘movement_reactions’, ‘mentality_composure’, ‘power_shot_power’, ‘mentality_vision’]scatter_matrix(fifa_df[attributes], figsize=(15,12))plt.show()
强相关关系往往是线性的,因此总体预测最有希望的属性是运动反应。从图中我们可以看出,运动反应和整体有很强的线性关系。
让我们仔细看看相关性散点图。
fifa_df.plot(kind=’scatter’, x=’movement_reactions’, y=’overall’, alpha=0.1, color=’red’)plt.show()
相关性确实很强;你可以清楚地看到一个上升趋势。
现在,是时候为 ML 算法准备数据了。
7.为 ML 算法准备数据
我将训练集和测试集分成独立的功能集和目标集。数据帧 y_train 和 y_test 包含目标值(目标值为整体),而 X_train 和 X_test 包含特征值(与目标值相关的所有其他属性)。
y_train = train_set['overall']
X_train = train_set.drop('overall', axis=1)
y_test = test_set['overall']
X_test = test_set.drop('overall', axis=1)
8.选择并训练一个模型
让我们首先使用 Scikit-Learn 的 LinearRegression() 函数训练一个线性回归模型:
from sklearn.linear_model import LinearRegressionlin_reg = LinearRegression()
lin_reg.fit(X_train, y_train)
让我们使用 Scikit-Learn 的 mean_square_error() 函数测量整个训练集上回归模型的 RMSE:
from sklearn.metrics import mean_squared_errory_predictions = lin_reg.predict(X_train)
lin_mse = mean_squared_error(y_train, y_predictions)
lin_rmse = np.sqrt(lin_mse)
lin_rmse**2.493574884183225**
分数还不错!!!似乎线性回归模型可以做到这一点。从散布矩阵中我们可以看出,并不是每个属性都有线性关系。对于非线性关系,我们需要一个更强大的模型,所以让我们训练一个决策树回归模型。这是一个强大的模型,能够发现数据中复杂的非线性关系。让我们使用 Scikit-Learn 的 DecisionTreeRegressor() 函数:
from sklearn.tree import DecisionTreeRegressortree_reg = DecisionTreeRegressor()
atree_reg.fit(X_train, y_train)
让我们再次测量模型的 RMSE:
y_predictions = tree_reg.predict(X_train)
tree_mse = mean_squared_error(y_train, y_predictions)
tree_rmse = np.sqrt(tree_mse)
tree_rmse**0.0**
什么?!0.0 的 RMSE!!!这是一个完美的模型吗?
实际上,可能是这个模型严重地过度拟合了数据。这就是为什么在每一个 ML 项目中,执行模型验证是很重要的,但是我们将在后面讨论。
现在,让我们只训练我们的最终模型,这是一个随机森林回归模型。
我们可以使用 Scikit-Learn 的 RandomForestRegressor() 函数训练一个随机森林回归模型:
from sklearn.ensemble import RandomForestRegressorforest_reg = RandomForestRegressor()
forest_reg.fit(X_train, y_train)
让我们看看这个模型的 RMSE:
y_predictions = forest_reg.predict(X_train)
forest_mse = mean_squared_error(y_train, y_predictions)
forest_rmse = np.sqrt(forest_mse)
forest_rmse**0.4774070457668509**
这是一个比我们的线性回归模型更好的分数,但不如我们的决策树模型。同样,这可能是我们的决策树模型严重过度拟合数据,这就是为什么我们总是需要在选择最佳模型之前验证每个模型。验证模型准确性的一个简单方法是使用 Scikit-Learn 的 K-fold 交叉验证功能。交叉验证将训练集随机分为 10 个不同的子集,称为折叠,然后它训练和评估模型 10 次,每次选择不同的折叠进行评估,并在 9 个折叠上进行训练。结果是一个包含 10 个评估分数的数组。在选择最佳模型之前,我们需要看一下平均验证分数。
让我们看看线性回归模型的交叉验证分数:
from sklearn.model_selection import cross_val_scorescores = cross_val_score(lin_reg, X_train, y_train,scoring='neg_mean_squared_error', cv=10)lin_reg_scores = np.sqrt(-scores)def display_scores(scores):
print("Scores:", scores)
print("Mean:", scores.mean())
print("Standard Deviation:", scores.std())display_scores(lin_reg_scores)**Scores: [2.48985397 2.509888 2.50910312 2.4642167 2.46189444 2.51445854 2.48370267 2.4734443 2.48382446 2.59475861]
Mean: 2.4985144826450054
Standard Deviation: 0.03662607159427437**
现在让我们看看决策树模型的交叉验证分数:
scores = cross_val_score(tree_reg, X_train, y_train,scoring='neg_mean_squared_error', cv=10)tree_scores = np.sqrt(-scores)display_scores(tree_scores)**Scores: [2.03976196 2.10100389 2.24933491 2.18751588 2.13289653 2.1158318 2.10529916 2.08391009 2.30935171 2.15395796]
Mean: 2.147886387907302
Standard Deviation: 0.07682311253910523**
现在这是一个比第一个更可信的分数。它仍然优于我们的线性回归模型,但让我们看看我们的随机森林模型的交叉验证分数:
scores = cross_val_score(forest_reg, X_train, y_train,scoring='neg_mean_squared_error', cv=10)forest_scores = np.sqrt(-scores)display_scores(forest_scores)**Scores: [1.29156727 1.24883845 1.2625419 1.288613 1.22436926 1.30612055 1.25621857 1.24755531 1.30399247 1.28656714]
Mean: 1.2716383911151843
Standard Deviation: 0.026074298378757566**
哇!!!这可能是我们见过的最好成绩。随机森林看起来很有前途。这是我们将在项目中使用的模型。
9.微调模型
既然我们已经选择了我们的模型,我们需要微调它。微调要求我们手动调整超参数,直到找到超参数值的最佳组合。微调是非常繁琐的工作,如果数据集很大,可能需要很长时间。你可能甚至没有时间去探索许多组合。Scikit-Learn 提供了一个更简单的选项,而不是手动完成所有事情。
您应该使用 Scikit-Learn 的 GridSearchCV 来搜索您,而不是手动摆弄超参数。你需要做的就是告诉它你想让它试验哪些超参数,试验什么,它会用交叉验证来评估超参数值的所有可能组合。下面的代码提供了我用来试验的参数。
from sklearn.model_selection import GridSearchCVparam_grid = [{'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]},{'bootstrap': [False], 'n_estimators': [3,10], 'max_features': [2,3,4]},]forest_reg = RandomForestRegressor() grid_search = GridSearchCV(forest_reg, param_grid, cv=5,scoring='neg_mean_squared_error',return_train_score=True) grid_search.fit(X_train, y_train)
训练完成后,你可以得到如下参数的最佳组合:
grid_search.best_params_**{'max_features': 8, 'n_estimators': 30}**
你也可以直接得到最佳估计量:
grid_search.best_estimator_**RandomForestRegressor(bootstrap=True, ccp_alpha=0.0, criterion='mse', max_depth=None, max_features=8, max_leaf_nodes=None, max_samples=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=30, n_jobs=None, oob_score=False, random_state=None, verbose=0, warm_start=False)**
当然,您可以用任何超参数值进行实验,但是我认为目前这样就可以了。
10.在测试集上评估模型
在调整了训练集上的模型之后,终于到了在测试集上评估最终模型的时候了。这个过程非常相似,但是这一次我们需要指定最终模型的最佳估计量。同样,我们需要测量最终模型的性能。完成这项工作的代码如下:
final_model = grid_search.best_estimator_
final_predictions = final_model.predict(X_test)
final_mse = mean_squared_error(y_test, final_predictions)
final_rmse = np.sqrt(final_mse)
final_rmse**1.135337798136083**
这个分数是我们迄今为止看到的最好的,更不用说它还被用于模型以前没有见过的数据。老实说,我没想到模型会做得这么好,但我们不能假设 RMSE 永远是某个值。我们想知道这个估计有多精确。为此,您可以使用 scipy.stats.t.interval() 计算泛化错误的 95%置信区间:
confidence = 0.95squared_errors = (final_predictions - y_test)**2np.sqrt(stats.t.interval(confidence, len(squared_errors)-1,loc=squared_errors.mean(),
scale=stats.sem(squared_errors)))**array([1.10181563, 1.16789818])**
我们可以看到 RMSE 将在 1.10 和 1.17 之间
95%的时候。
我们已经基本上完成了这个模型,但是出于好奇,我们想看看预测和实际目标有什么不同。为此,只需从测试集中选择五个实例,并在最终模型上使用 predict() 方法:
some_data = X_test.iloc[:5]
some_label = y_test.iloc[:5]print("Predictions:", final_model.predict(some_data))
print("Labels:", list(some_label))**Predictions: [64.2 73.8 68.76666667 68.13333333 63.4 ]
Labels: [64, 74, 69, 68, 63]**
预测相当准确。我很惊讶模型表现得这么好。我对结果非常满意。
结论
这个项目告诉我们,我们可以建立一个 ML 模型来预测一个球员的总体 FUT 评级。这个项目制作起来很有趣,我从中学到了很多。我对 ML 及其提供的所有可能性充满热情。我很高兴能在这个领域探索更多,并在这个过程中学习一切。我希望你喜欢这篇文章,也许有一天你可以开始自己的 ML 项目!!!
一个 Docker 映像的十五个 Jupyter 笔记本扩展
我们的Jupyter****Python和 R 用户的 Docker 图像要求他们在每次启动后设置自己的Nbextensions
偏好。我们能够通过在 Docker 映像中设置常用的Nbextensions
首选项来提高 Jupyter 笔记本用户的工作效率。
一个显示 ggplot 图的 R 代码 Jupyter 笔记本。资料来源:Giphy
1.3.0 版本开发人员的目录结构
我们有一个共享磁盘,任何人都可以将模板文件复制到他们的本地目录结构中。
|-- dockerSeasons
|-- dev
|--- Dockerfile
|--- docker-compose.yml
|-- test
|--- Dockerfile
|--- docker-compose.yml
开发和测试的每个成员将版本 1.3.0 dockerSeasons
目录复制到他们的PROJECTS
目录中。
- PROJECTS
.
.
.
|-- <project-name>
|-- dockerSeasons
|-- dev
|--- Dockerfile
|--- docker-compose.yml
|--- README.md
|--- <ln> requirements.txt
|-- test
|--- Dockerfile
|--- docker-compose.yml
|--- README.md
|--- <ln> requirements.txt
|-- src
|-- test
|--- requirements.txt
|--- README.md
.
.
注意: Dev 1.0.3 可以使用 0.0.3 PROJECTS
目录结构不变。版本 3.0.1 dockerSeasons
会覆盖docker
0.0.3 目录。
测试针对 Python 包中他们需要和不需要的差异修改<project-name>/requirements.txt
。然后测试象征性地将<project-name>/requirements.txt
(在<project-name>/dockerSeasons/test
目录中)与命令链接起来:
*# MacOS and linux variants
$ ln ../../requirements.txt requirements.txt*
在测试目录中唯一不同的是文件requirements.txt
,目录dockerSeasons/test/
中的文件。测试将此目录结构移动到阶段服务器和 3 个冗余生产服务器。服务器场是内部的。
1.0.3 发布了一个dockerfile
模板,使 Dev 和 Test 能够通过requirements.txt.
定制每个 Docker 图像
Docker 图像的 1.3.0 版本
在之前的文章中,我展示了用于用 Jupyter notebook 创建 Docker 图像的Dockerfile
。我们现在在 DES 1 . 3 . 0(DockerEenterpriseSsolution)上,为 Jupyter 笔记本用户提供了不同规格的Dockerfile
。
有意义的变化是在requirements.txt.
之后的jupyterthemes (nbextentsions)
阶段,通过试验和反馈,我们发现 Dev 和 Test 改变requirements.txt
的频率比jupyterthemes
低。
将分段的顺序从较不频繁的更改更改为较频繁的更改,这允许我们利用 Docker 缓冲。结果是比以前更快的Dockerfile
版本。
根据requirements.txt
中的内容,我们会经历长达 10 分钟的完整构建。通过将jupyterthemes
放在最后,我们经历了大约 30 秒的构建(没有requirements.txt
变化)。
您可能会考虑Dockerfile
构建中的变更频率和构建顺序。
部分Dockerfile
的 DES 1.3.0 版本为:
**FROM** python:3.7
**FROM** jupyter**/**minimal-notebook
**WORKDIR** $*HOME* **RUN** python **-**m pip install **--**upgrade pip
**COPY** requirements.txt .**/**requirements.txt
**RUN** python **-**m pip install **-**r requirements.tx
**RUN** python **-**m pip install **--**upgrade **--**no-deps **--**force-reinstall notebook
#
**RUN** python **-**m pip install jupyterthemes
**RUN** python **-**m pip install **--**upgrade jupyterthemes
**RUN** python **-**m pip install jupyter_contrib_nbextensions
注意:不要而不是从你的终端外壳执行以下命令。如果你这样做了,你在你的本地副本 jupyter 中安装jupyterthemes
。 更大的 问题是你在 jupyter 的本地副本中重置了你的本地nbextentsions
设置。
pip install jupyterthemes
pip install **--**upgrade jupyterthemes
pip install jupyter_contrib_nbextensions
有哪些Nbextensions
可用?
我们必须分两步构建Dockerfile
,因为我们需要找到可用的jupyterthemes
以及它们的名称。首先,我们执行了上面列出的部分Dockerfile
。
我们使用命令updev
启动了 juptyer (将在本文稍后描述)。然后,我们在 Jupyter 笔记本上运行了以下内容。
!jupyter nbextension list
输出-> >
Known nbextensions:
config dir: /home/jovyan/.jupyter/nbconfig
notebook section
nbextensions_configurator/config_menu/main enabled
- Validating: problems found:
- require? X nbextensions_configurator/config_menu/main
contrib_nbextensions_help_item/main enabled
- Validating: OK
jupyter-js-widgets/extension enabled
- Validating: problems found:
- require? X jupyter-js-widgets/extension
jupyter-notebook-gist/notebook-extension enabled
- Validating: problems found:
- require? X jupyter-notebook-gist/notebook-extension
autosavetime/main enabled
- Validating: OK
codefolding/main enabled
- Validating: OK
code_font_size/code_font_size enabled
- Validating: OK
code_prettify/code_prettify enabled
- Validating: OK
collapsible_headings/main enabled
- Validating: OK
comment-uncomment/main enabled
- Validating: OK
equation-numbering/main enabled
- Validating: OK
execute_time/ExecuteTime enabled
- Validating: OK
gist_it/main enabled
- Validating: OK
hide_input/main enabled
- Validating: OK
spellchecker/main enabled
- Validating: OK
toc2/main enabled
- Validating: OK
toggle_all_line_numbers/main enabled
- Validating: OK
tree section
nbextensions_configurator/tree_tab/main enabled
- Validating: problems found:
- require? X nbextensions_configurator/tree_tab/main
config dir: /opt/conda/etc/jupyter/nbconfig
notebook section
plotlywidget/extension enabled
- Validating: OK
现在我们有了要添加到 1.3.0 版本中的Nbextensions
名称dockerfile
!
jupyter 扩展的 docker 文件
开发的dockerfile
启用了注释# enable the Nbextensions.
后显示的以下Nbextensions
**FROM** python:3.7
**FROM** jupyter**/**minimal-notebook
**WORKDIR** $*HOME* **RUN** python **-**m pip install **--**upgrade pip
**COPY** requirements.txt .**/**requirements.txt
**RUN** python **-**m pip install **-**r requirements.tx
**RUN** python **-**m pip install **--**upgrade **--**no-deps **--**force-reinstall notebook
#
**RUN** python **-**m pip install jupyterthemes
**RUN** python **-**m pip install **--**upgrade jupyterthemes
**RUN** python **-**m pip install jupyter_contrib_nbextensions
**RUN** jupyter contrib nbextension install **--**user
# enable the Nbextensions
**RUN** jupyter nbextension enable contrib_nbextensions_help_item**/**main
**RUN** jupyter nbextension enable autosavetime**/**main
**RUN** jupyter nbextension enable codefolding**/**main
**RUN** jupyter nbextension enable code_font_size**/**code_font_size
**RUN** jupyter nbextension enable code_prettify**/**code_prettify
**RUN** jupyter nbextension enable collapsible_headings**/**main
**RUN** jupyter nbextension enable comment-uncomment**/**main
**RUN** jupyter nbextension enable equation-numbering**/**main
**RUN** jupyter nbextension enable execute_time**/**ExecuteTime
**RUN** jupyter nbextension enable gist_it**/**main
**RUN** jupyter nbextension enable hide_input**/**main
**RUN** jupyter nbextension enable spellchecker**/**main
**RUN** jupyter nbextension enable toc2**/**main
**RUN** jupyter nbextension enable toggle_all_line_numbers**/**main
Docker-Compose 命令和 docker-compose.yaml 文件
Docker-Compose 用于为同一个应用程序同时管理几个容器。这个工具提供了与 Docker 相同的功能,但是允许你拥有更复杂的应用程序。
插图由雷切尔·科特曼
Docker-Compose 可以将多个 Docker 容器合并成一个运行时映像。目前,我们只对一个 Docker 图像(dockerfile.yaml
)使用 Docker-Compose 。
**version**: '3'
**services**:
**dev**:
**build**: '.'
**ports**:
- "127.0.0.1:8889:8888"
**volumes:
- ../../../.:/docker**
**working_dir**: /docker
注意:当您使用命令updev
(将在本文后面描述)时, docker-compose 命令volume:
**- ./../../.**
会导致<path-to-projects>
被映射到**/docker**
,即 docker 映像的内部目录。随后推出的 jupyter 使用<path-to-projects>
作为其顶级目录。请使用上面显示的示例目录结构,或者用您自己的本地目录结构代替**- ./../../.**
。
自动化常用的 docker-compose 命令
Docker命令通过将以下命令添加到˜/.bashrc_profile
或˜/bashrc.txt.
来设置
devdir='<path-to-projects>/photon/photonai/dockerSeasons/dev/'
testdir='<path-to-projects>/photon/photonai/dockerSeasons/test/'echo $devdir
echo $testdirexport testdir
export devdir#
alias updev="(cd $devdir; docker-compose up) &"
alias downdev="(cd $devdir; docker-compose down) &"
alias builddev="(cd $devdir; docker-compose build) &"#
alias uptest="(cd $testdir; docker-compose up) & "
alias downtest="(cd $testdir; docker-compose down) &"
alias buildtest="cd $testdir; docker-compose build) &"
如果找不到文件˜/bashrc.txt
,用 touch ˜/bashrc.txt.
( MacOs 或各种 Linux 或 Unix 操作系统之一创建它。)
注意:当你完成编辑时,记得按source
˜/.bashrc_profile and/
或˜/bashrc.txt
。
updev
命令在我的终端控制台上产生了以下消息流。(你的会有不同的时间戳和其他细微差别。)
dev_1 | [I 15:53:33.389 NotebookApp] [jupyter_nbextensions_configurator] enabled 0.4.1dev_1 | [I 15:53:33.817 NotebookApp] JupyterLab extension loaded from /opt/conda/lib/python3.7/site-packages/jupyterlabdev_1 | [I 15:53:33.818 NotebookApp] JupyterLab application directory is /opt/conda/share/jupyter/lab**dev_1 | [I 15:53:34.196 NotebookApp] Serving notebooks from local directory: /docke**rdev_1 | [I 15:53:34.196 NotebookApp] The Jupyter Notebook is running at:dev_1 | [I 15:53:34.196 NotebookApp] [http://dd974d01052d:8888/?token=78824facb945e1bf386a6ead41f7b147d5ac4240dc673421](http://dd974d01052d:8888/?token=78824facb945e1bf386a6ead41f7b147d5ac4240dc673421)dev_1 | [I 15:53:34.196 NotebookApp] or [http://127.0.0.1:8888/?token=78824facb945e1bf386a6ead41f7b147d5ac4240dc673421](http://127.0.0.1:8888/?token=78824facb945e1bf386a6ead41f7b147d5ac4240dc673421)
注意:updev
命令输出:
.
.
h[ttp://127.0.0.1:**8888**/?token=12377aa1c91b45e66e45eb5d5bdf2115cad2dae5b61be5c0](http://127.0.0.1:8888/?token=12377aa1c91b45e66e45eb5d5bdf2115cad2dae5b61be5c0)
因为我们在dockerfile.yaml
中将端口8888
映射到端口8889
( Dev )和端口8890
( Test )。DET 1.3.0 版本的用户必须将以下内容剪切并粘贴到他们的 web 浏览器中。
h[ttp://127.0.0.1:**8889**/?token=12377aa1c91b45e66e45eb5d5bdf2115cad2dae5b61be5c0](http://127.0.0.1:8888/?token=12377aa1c91b45e66e45eb5d5bdf2115cad2dae5b61be5c0)
摘要
对于“将 Jupyter 笔记本扩展添加到 Docker 映像”来说,这看起来是不是太详细了也许是吧。我重述一下:
- 在 Jupyter user
Dockerfile.
中添加你想要的Nbextensions``Nbextensions
名称以及如何启用它们已在上面给出。 - 如有必要,编辑
dockerfile.yaml volume:
**- ./../../.**
。随后推出的 jupyter 使用<**./../../.**
作为其顶级目录。 - 可选地,通过将常用的 docker-compose 命令添加到您的
˜/.bashrc_profile
文件中来“自动化这些命令”。 - 最后,启用
Nbextensions
:
所有的Nbextensions
都被禁用。您必须手动启用码头集装箱下水。不酷!瑞秋·科特曼的动画
DET 1.3.0 版本的发布经历了几天的曲折和错误。我希望你花更少的时间来实现你的解决方案,这篇文章对你的努力有所帮助。
如果你有建议或改进,请评论。
我使用的 Docker 实现的更多细节在:
https://medium.com/swlh/a-docker-solution-for-the-enterprise-7b5d2942b43a https://medium.com/@dr.bruce.cottman/a-docker-solution-for-the-test-groups-use-cases-8e8ed6c28e11
注意:你可以从可克隆的 GitHub repo 中改编 Docker 代码到你的项目中。
填补时间序列数据中的空白
使用熊猫作为时间序列数据准备的一个步骤进行重新采样
时间序列数据并不总是完全清晰的。有些日子可能会有间隙和缺失值。机器学习模型可能不需要数据缺口,您需要在数据分析和清理过程中填充缺失的值。本文将介绍如何使用 pandas 重采样方法来识别和填补这些空白。
原始资料
出于演示的目的,我模拟了一些每日时间序列数据(总共 10 天的范围),其中有一些有目的的缺口。初始数据如下所示:
初始数据集,按作者分类的图像
再取样法
pandas 中一个强大的时间序列功能是重采样功能。这允许我们指定一个规则来对时间序列进行重采样。
如果我们在同一粒度上调用重采样,这种重采样功能对于识别和填充时间序列数据中的间隙也很有用。例如,我们正在处理的原始数据集有间隙,并且不是每天都有值。如下利用重采样功能将这些间隙识别为 NA 值。
简单的重新取样,作者的图像
简单的重采样图表,作者图片
正如您将在上面看到的,重采样方法为不存在的日期插入 NA 值。这扩展了我们的数据框架,并从本质上确定了需要处理的差距。下一步是根据各种方法用实际数字填充这些 NA 值。
正向填充重采样
填充缺失值的一种方法是向前填充。使用这种方法,直接在前的值用于填充缺失的值。例如,我们的数据中缺少第二个到第四个,将用第一个的值(1.0)填充。
正向填充重采样,按作者排序的图像
向前填充图表,按作者排序的图像
反向填充重采样
类似的方法是反向填充。完成上述操作后,您可能会猜到这是做什么的——使用 After 值来填充缺失的数据点。不是用我们时间序列中第一天的 1.0 来填充第二天到第四天,您将在下面看到它现在的值是 2.0(从 10 月 5 日开始)。
反向填充重采样,按作者排序的图像
反向填充图表,按作者排序的图像
插值填充重采样
本文中的最后一种方法是内插法。下图显示了插值,其中数据基本上是从一个点到下一个点的拟合。您将在下面的示例中看到平滑的线条连接缺失的值。
插值重采样,作者图像
插值填充图表,按作者排序的图像
摘要
有许多方法可以识别和填补时间序列数据中的空白。重采样功能是一种识别并填充缺失数据点的简单方法。这可以用来在建立机器学习模型之前准备和清理数据。
所有的例子和文件都可以在 Github 上找到。
填补空白:三种插补方式
小窍门
观察缺失数据的插补,从简单的替换方法到更复杂的链式方程多重插补。
背景
如果你做过任何预测分析——或尝试过任何 IFoA 精算检查——你会遇到“垃圾进,垃圾出”这句话。自 20 世纪 50 年代末以来,它就一直存在,并抓住了这样一个概念,即如果逻辑的基本前提有缺陷,那么逻辑就是不合理的。
这句话同样适用于预测建模:无论算法有多花哨,数据质量总是一个限制因素。
我的新闻提要贴满了对最新算法和超参数优化技术的解释,但我很少看到任何关于数据清理的内容。这真的不奇怪,因为大多数分析师可能会发现数据管理是治疗他们失眠的有效方法。然而,这是建模过程中至关重要的一部分,需要极大的关注和思考。
我最近一直在处理一些外部数据源,这些数据源在与公司内部数据结合后需要进行大量处理,这主要是因为合并和聚合后的数据中存在大量缺失值。以下注释旨在通过一个例子来分享我从处理恶意数据的实践经验中学到的一些东西,包括:
- 归罪背后的动机
- 简单看一下标准的估算方法
- 更长远地看待更复杂的方法
归罪
先说处理缺失值,这本身就是统计学的一个广阔领域。
为什么我们需要烦恼?
很简单,缺少值就是信息缺口。
充其量,这些信息差距
- 可能无法让我们获得关键见解或…
- 可能导致从数据中得出的任何见解的严谨性值得怀疑或…
- 可能会描绘出一幅有限的世界图景(想想试图通过钥匙孔来描述一个房间)。
…在最坏的情况下,它们是导致糟糕的机器学习模型的障碍——垃圾进,垃圾出。
缺失的值可能会让我们深入了解我们的问题
讽刺。
理解值丢失的原因有时可以让我们更好地理解我们的数据和数据收集协议。我喜欢问自己以下问题,因为我发现这些问题经常让我更好地理解我在做什么,以及如何对待缺失的价值观。
“数据是随机缺失的吗?”也就是说,缺失的价值观中是否存在某种模式或系统性偏差?
“为什么数据会丢失?”缺失的数据是由数据收集方式造成的吗?比如数据检索管道是否正确?是否存在匹配问题?
丢失的数据是收集数据的时间段的函数吗?例如,多年数据集只能提供特定时间范围的数据。
“缺失的值能告诉我们什么吗?”也就是说,当我们想到特性本身时,缺失的值是否意味着什么?
如果我们正在查看房屋销售价格数据,“公摊面积”特性中缺失的数据是否能告诉我们一些关于房子的信息?可以说,是的——这可能意味着房子没有游泳池。
如果我们从一个有足够市场覆盖面和良好匹配协议的大型提供商那里寻找信用评分数据,缺失的信用评分是否能告诉我们一些关于客户的信息?最有可能的是,该客户尚未建立信用记录,可能是因为他们年轻或刚刚移民。只用现金支付商品和服务可能是一个危险信号!
一旦我们弄清楚了这些问题,我们就可以继续决定一个“最优”策略来处理缺失的价值。现在,我不打算这样做,因为(A)这超出了本笔记的范围,( B)我实际上对我们正在处理的数据集了解不多。
让我们继续讨论一些方法来弥补我们缺失的价值观。
三种估算方法:
一个简单的方法是删除任何包含缺失值的行。这并不理想,因为从我们的数据集中删除观察结果实际上是从我们的数据集中删除信息。
一个更复杂的方法是用从没有丢失的值计算出的统计值代替丢失的值。
- 这可以通过在数据组中加入额外的列来增强,这些列表明一行是否被估算。例如,如果我们在
Column A
中输入缺失值,我们可以创建一个名为Column A Imputed
的新列,当Column A
中的一行被输入时,它取值 1,否则取值 0。 - 通过考虑背景信息,可以产生更复杂的插补。例如,假设我们正在处理一个住房数据集,我们试图估算与房子花园大小相关的缺失数据。由于同一街区大约在同一时间建造的房屋很可能具有相似的特征,因此用同一街区大约在同一时间建造的房屋的平均花园面积来代替缺失值并非不合理。
一种高级方法是使用非缺失数据迭代地模拟缺失值。
- 例如,假设我们的数据集中有 10 列。还假设丢失了 10%的
Column 1
,丢失了 5%的Column 2
,丢失了 2.5%的Column 3
,并且在数据集中没有其他丢失的值。 - 我们可以使用第 4-10 列来建立一个预测
Column 3
的模型。这个模型将使用没有丢失Column 3
数据的行来构建。 Column 3
中缺失的值将被模型预测替换。- 然后,我们重复建模过程,使用第 3–10 列来预测
Column 2
。同样,只使用非缺失数据,并且Column 2
中缺失的值将被我们模型中的预测所替换。 - 最后,我们可以为
Column 1
重复建模-插补过程。 - 插补顺序通常从最少缺失值的列开始,并按照缺失值递增的顺序移动。
- 这通常会提高插补模型的预测能力,因为它们是用更多的数据构建的,而且插补值中包含的不确定性更少。
- 这种方法被称为使用链式方程的多重插补(MICE ),在文献中有详细介绍——我鼓励您阅读!
好吧,但是我们怎么知道最好的估算方法是什么呢?
如果我们在一个项目的开始,我们可能很难确切地知道哪种估算方法是最好的。此外,我们可能不知道是否有单一的最佳方法,或者是否需要某种混合方法。
无论如何,我们需要定义我们所说的“最好”是什么!
在这篇笔记中,我试图根据我们掌握的其他信息来预测水是否可以饮用。我已经决定(感谢其他 Kagglers 所做的伟大工作)我将使用一个极其随机的森林来做预测,并且我将使用各种度量来测量树模型的准确性。
补充说明:您可能认为知道为哪种模型形式进行优化有点骗人。你可能是正确的,因为对于大多数机器学习应用来说,通过交叉验证进行模型选择是标准的。然而,提前知道将使用什么模型在现实世界中并不罕见——实践者经常受到技术和他们的涉众环境的限制(关于这些的讨论可以写在单独的文章中)。
回到笔记!
我将把最佳插补方法定义为在所选模型指标中最大化树形模型交叉验证模型准确性的方法。
我还定义了我将应用的 5 种估算方法:
- 删除所有缺少值的行。
- 使用基于非缺失值的统计数据输入缺失值。
- 如(2)中那样进行估算,但是添加了附加列来指示是否估算了特定值。
- 使用贝叶斯岭模型的 MICE 方法。
- 一只老鼠用一个非常随机的森林模型接近。
工作流程
- 获取数据。
- 做插补。
- 创建交叉验证功能。
- 使用模型准确性度量和特征重要性评估估算数据集的性能。
- 选择我们的最佳估算方法。
我们走吧!
数据
来源于 Kaggle ,我们将使用饮用水数据集作为例子。让我们快速看一下数据中的内容:
- pH 值:表示酸性或碱性水状态。
- 硬度:主要由钙和镁盐引起,因为水溶解了它通过的物质中的地质沉积物。
- 固体:水可以溶解多种矿物质和盐类,如钾、钙、钠;溶解的矿物质会产生令人不快的味道和稀释的外观(使用水的重要参数)。
- 氯胺:氯和氯胺是公共供水系统使用的消毒剂。
- 硫酸盐:在矿物、土壤和岩石中发现的自然存在的物质。
- 导电性:纯水不是电流的良导体;离子浓度的增加增强了水的导电性
- 有机碳:来自腐烂的天然有机物和合成来源,这是对纯水中有机化合物中碳总量的度量。
- 三卤甲烷:三卤甲烷是在用氯处理过的水中发现的化学物质。饮用水中 THMs 的浓度根据水中有机物质的水平、处理水所需的氯量和被处理水的温度而变化。
- 浊度:是水的发光特性的量度,该测试用于指示与胶体物质相关的废物排放质量。
- 可饮用性:表示水对于人类饮用是否安全,其中
1
表示可饮用,0
表示不可饮用。
数据的第一行如下所示:
作者图片
我们可以看到有一些丢失的值,但是到底有多少呢?
作者图片
目标(potability
)没有遗漏——这是好事!
不幸的是,ph
、sulfate
和trihalomethanes
就不一样了,它们分别丢失了 15%、24%和 5%的数据。
我们不会在数据转换和特性工程上花太多心思,但不管怎样,至少对我们正在做的事情有个感觉是个好习惯。
作者图片
因此,水的特征似乎大致呈正态分布,当观察可饮用/不可饮用的划分时,有一些明显的差异。在其他情况下,我们可能会对调查*ph*
*chloramines*
和* *sulfate*
感兴趣。*
快速检查水可饮用性的正面和负面情况之间的平衡显示出轻微的不平衡(39%的情况属于“正面”类别)。
我将暂时离开不平衡问题,因为它不会对我们的归因调查产生太大的影响。
建模和验证拆分
我们将获取初始数据集,并将其分为训练数据集和验证数据集。
我们知道有些数据丢失了,所以我们需要小心到底哪些行进入了验证集——我们不希望在我们的验证集中有丢失的值。
这个过程相对简单:
- 打乱数据以删除原始数据中固有的任何顺序。
- 检查哪些行包含缺失值。
- 决定我们需要多少干净的数据来验证。我将选择 600 行进入我们的验证集——这大约是数据集的 20%,完全符合标准。
- 从原始数据中分离干净的验证数据,并将其命名为
X_valid
和Y_valid
。 - 剩余的数据形成了我们的训练集
X
和Y
。
就代码而言,这看起来类似于:
现在检查验证集中是否没有丢失的值…
作者图片
太棒了。
我们正在使用所有可用的数据(即X
∩X_valid
=df
),我们的验证集不包含缺失值。我们可以继续处理训练集中缺失的值。
创建估算数据集
删除所有缺少值的行
删除缺少值的行非常容易。然而,按照这种方法,我们丢失了大约 49%的数据,这显然是站不住脚的。
虽然一些数据丢失是可以接受的,但是这个数量是不可接受的,因此我们将不再考虑这种方法。
用统计值(中值)替换缺失值
这是一种稍微复杂一点的方法,它允许我们保存更多的信息,而不仅仅是删除行。
由于所有的数据都是连续的,我们可以使用描述连续变量的统计数据;在这种情况下,我使用中值,它比平均值对异常值更稳健。
如果我们的一些数据是分类的,我们将需要修改我们的统计-我的第一选择将是使用模式(即最受欢迎的值)。
然而,这种估算很简单:
用统计数据替换缺失值,并添加指标来识别估算值
基于前面的方法,我们首先确定要估算的观测值,然后进行估算。通过对代码做一点小小的修改,我们可以将指示器列添加到数据中,这样我们的模型就可以识别被估算的行。
用 MICE 方法替换缺失值
我们今天要探讨的最复杂的方法是,我们现在将对非缺失值进行建模,并用模型预测替换缺失值。同样,我们的数据类型决定了我们的方法:我们试图建模的数据是连续的,因此我们将进行回归。
我们将使用方便的sklearn
实现来:
- 用贝叶斯岭模型估算缺失值(
BayesianRidge
)。 - 用一个极其随机的森林来估算缺失值(
ExtraTreesRegressor
)。如果我们的一些数据是分类的,我们需要使用分类类而不是回归类。
构建交叉验证功能
我们现在准备构建功能,创建折叠外模型预测以及每个折叠的特征重要性。
这将使我们了解哪种估算方法产生的模型最准确,并让我们深入了解该模型是如何构建的。
这是一段很长的代码,但是很容易理解:
评估交叉验证的性能和功能重要性
让我们绘制每个数据集的每个特征的特征重要性等级。这里,我们将使用所有数据集共有的特性。
作者图片
有意思!
建立在Tree Impute
、Fill
和Bayesian Impute
数据集上的模型似乎在很大程度上同意对提高模型拟合度很重要的特征。
基于Fill + Indicate
数据构建的模型似乎在哪些功能最重要的问题上存在分歧,但值得记住的是,这个数据集比其他数据集拥有更多的功能。让我们来看看Fill + Indicate
中所有特性的重要性。
作者图片
“原始”栏特征重要性的不同排序,其中sulfate
、ph
、trihalomethanes
的插补指标也发挥了作用。这真的很有趣,因为这些列有缺失值,所以模型使用估算列和指标列来学习。
模型中没有使用其他指标列,这些指标列的特征重要性值为 0,因此排在最后。
让我们检查一下跨褶皱的模型准确性指标。在这种情况下,我们将使用准确度,它被定义为%正确预测。
作者图片
现在来看看折页数据的所有精确度指标。
作者图片
作者图片
这就是我们拥有的模型预测能力的非折叠度量,其中:
accuracy
是模型精度,定义为正确预测的百分比;越高越好。f1 score
是精度和召回率的调和平均值;越高越好。balanced accuracy
是对每一类的平均回忆;越高越好brier score
是预测概率与实际结果的均方差;越低越好。
对我来说,这看起来像树插补方法是上面定义的最佳方法!
一些想法
总结,夹杂一些散漫。
我们已经讨论了为什么我们需要估算数据,触及了我最喜欢的一个成语(“垃圾进,垃圾出”)。
没有花太多时间了解数据。我不鼓励这样做,在现实世界中我自己也不会这样做。领域知识和数据理解通常是成功分析实践的关键驱动因素。
我们使用多种技术估算缺失的数据。通过pandas
可以轻松应用简单的技术,而通过sklearn
可以进行更复杂的插补。就像生活中的其他事物一样,并非所有闪光的东西都是金子,不新奇的东西也不应该立即丢弃。这是显而易见的,因为我们看到用中值替换缺失值(“填充”技术)产生了极具竞争力的结果!
虽然我没有详细介绍交叉验证步骤,但是交叉验证是一个很好的工具,可以充分利用你的(有时是有限的)数据。我强烈推荐在现实场景中明智地实现它。
重要的是要记住模型的准确性——无论它是如何定义的——并不是从业者应该关心的唯一事情。数据的变更很可能会对模型结构产生重大影响,我们通过各种插补技术的特征重要性差异看到了这一点。
我们使用了多种模型准确性指标来评估插补方法的性能。这样做提供了不同的视角,我们可以通过这些视角来观察模型的性能。同样,如果可行的话,我会建议在现实世界中这样做。关注最适合当前场景的指标是最务实的,因为例如 I 型和 II 型错误可能会有财务影响。
最后,但同样重要的是,我希望你喜欢这篇文章,就像我喜欢把它放在一起一样!
根据对象内容过滤熊猫数据帧
如果你对筛选熊猫数据框的许多方法感到困惑,这篇短文就是为你准备的!
来自维基百科的米尔科·葛军博士拍摄的弗雷姆模型。根据 CC BY-SA 3.0 获得许可。
首先,什么是数据帧?DataFrame 是带有潜在不同类型的列的二维标记数据结构。这个概念类似于关系数据库中的表。也就是说,如果你只存储原子值。然而,作为一个 Python 库,DataFrame 很自然地将对象存储在其单元中。在关系数据库中,这通常被认为是一种不好的做法,因为它打破了第一范式,大大增加了 SQL 查询的复杂性。在 Python 中不是这样!本文用工作代码示例解释了在存储 Python 对象时不同的过滤方法是如何工作的。
使用掩码过滤标量数据
让我们看看如何从数据帧中选择数据的不同方法。
我们可以选择该数据帧中的行并进行投影(选择列)。行选择应该产生一个布尔掩码,它只是一个长度与 DataFrame 的行数匹配的布尔数组。我们将使用这个掩码,通过 DataFrame 的 [] 操作符来说明我们希望保留哪些行。
使用访问者
掩码通过操作符重载的魔力工作。通过对投影结果和一个标量值应用 > 操作符,我们自动映射一个一元函数,在前者上有一个布尔返回类型。这不适用于更复杂的数据类型。熊猫通过使用 访问器 对象来解决它。让我们看看字符串访问器 str 是如何工作的:
对于列表和字典等 Python 对象,Pandas 中提供的默认访问器可能还不够。虽然我们可以定义一个自定义的访问器,但是这样做可能不值得,因为有很多方法可以在没有访问器的情况下处理行。
让我们扔掉我们的玩具数据框架,创建一个新的适合为监督机器学习标记样本的任务。如果您已经做到了这一步,我将假设您熟悉这个用例。我们将创建一个 DataFrame,它可以存储关于哪个注释者用哪个标签标记了样本的信息。有了这个数据模型,很容易计算统计数据,比如注释者协议和 kappas!
哇,那里发生了很多事!让我们一起一点一点地熬过来。
通过使用 iloc 索引器选择一对熊猫 切片对象 (第一个用于行,第二个用于列)的标签列,开始屏蔽。 apply 函数对由 系列 对象表示的行(由轴=1 参数决定)进行迭代,并将一元函数映射到每一行。本质上是一个映射函数在一个列表上做的事情。我们将函数定义为 Python lambda 函数,没有什么特别的。在函数内部,我们访问每个单元格中的数据并测量其长度。为了创建行的过滤掩码,我们需要使用 Python any 函数连接每个单元格的结果。就是这样!
我们可能需要做更复杂的事情,这些事情不适合 lambda 函数。
没问题!创建您自己的接收行的函数,并自己处理它。我们可以使用这样一个函数来确定不同的注释者不同意哪一行。
我们还可以根据条件选择列。
允许它的巧妙技巧是 栈 函数。与显式指定列相比,我们不仅可以选择整行,还可以根据对数据评估的一些条件来选择列。stack 函数旋转数据帧,使该列成为新的多级索引的一部分,并将该行拆分为具有单个值的多行。让我们把这个相当抽象的想法付诸实践。
到目前为止,我们存储的所有对象都是列表,但是我们也可以使用其他类型和自定义类。例如,让我们使用字典。
总之,
我们已经介绍了通过应用过滤掩码来过滤标量和 Python 对象上的 Pandas 数据帧。对于标量,我们通过使用重载操作符来创建它们,对于对象,通过使用内置的访问器和 apply 函数来创建它们。我们还描述了通过定义一个定制的过滤函数来基于列的动态组合进行过滤。最后,我们探索了通过栈函数使用旋转来动态选择列。
作为结束语,我想讨论一下在数据帧中存储对象的用处。在我看来,当建立一个关系数据库是多余的时候,它可能是一个合适的数据存储解决方案。这可能是典型的几百行长的用于机器学习的 Python 脚本,或者是一个快速而肮脏的 Flask 注释工具。从磁盘存储(和加载)数据帧只需要一次函数调用(例如df . to _ CSV(‘文件名’))。我认为这是将这些数据存储在 Python 字典中的更好的替代方法,因为后续的查询更加优雅。使用字典时,查询很可能采用 for 循环的形式,这种形式比 DataFrame 查询可读性差,也更容易出错。通过为每一列指定一种数据类型,使用 DataFrames 还可以强化良好的数据模型设计实践。
希望这篇文章能帮到你。欢迎任何意见和改进建议!
按位置过滤推文
账户位置元数据+正则表达式==推文位置过滤
内森·杜姆劳在 Unsplash 上的照片
在我的最新项目中,我探索了这个问题“在新冠肺炎·疫情期间,美国公众对 K-12 学习的看法如何?”。使用从 Twitter、自然语言处理和监督机器学习收集的数据,我创建了一个文本分类器来预测推文对这个话题的情绪。
因为我想了解美国的情绪,所以我需要按地点过滤推文。Twitter 开发者网站在可用选项上提供了一些很好的指导。
我选择使用帐户位置地理元数据。以下是来自 Twitter 开发者网站的详细信息:“基于用户在其公开资料中提供的‘家’的位置。这是一个自由格式的字符字段,可能包含也可能不包含可进行地理引用的元数据”。
在我们开始之前,这里有一些警告:
- 由于账户位置不能保证被填充,你必须接受你可能会错过相关推文的事实。
- 我使用方法依赖于包含美国标识符(比如有效的美国州名)的帐户位置。
如果你能接受这些警告,请继续阅读。😃
在我分享实际代码之前,我先简要介绍一下我的方法:
- 我创建了一个 Python 脚本来监听 Twitter 流中与我感兴趣的主题相关的推文。
- 在收到一条 Tweet 时,我获得帐户位置属性,并使用正则表达式检查它是否是美国的位置。
- 通过位置检查的 Tweets 将通过我的代码进行进一步处理。(在我的例子中,我将 Tweet 存储在 MongoDB 集合中。)
现在我已经分享了整个工作流程,让我们看看一些代码。
我的脚本使用了一个 tweepy。StreamListener 用于从 Twitter 流中收听传入的推文。神奇的事情发生在我的 StreamListener 的 on_status 函数中。
def on_status(self, tweet):
# Checking tweet for likely USA location
is_usa_loc = self.get_is_usa_loc(tweet) if is_usa_loc:
# insert the tweet into collection
twitter_collection.insert(tweet_doc)
else:
print(‘Could not determine USA location’) def get_is_usa_loc(self, tweet):
is_usa_loc = False
if tweet.user.location:
user_loc_str = str(tweet.user.location).upper()
is_usa_loc = re.search(usa_states_regex, user_loc_str) or re.search(usa_states_fullname_regex, user_loc_str)
return is_usa_loc
在 on_status 内,我调用一个助手函数: get_is_usa_loc 。在这个助手函数中,我首先检查以确保账户位置确实在 Tweet 中填充。如果是这样,我将 Account Location 转换为大写字符串,并对照两个正则表达式进行检查。一个正则表达式检查美国各州的双字符缩写。另一个正则表达式检查美国各州的全名。帐户位置只需匹配一个。😃
以下是我使用的正则表达式。第一个是州名缩写,第二个是州名全称和术语“美国”。
usa_states_regex = ‘,\s{1(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])’ usa_states_fullname_regex = '(ALABAMA|ALASKA|ARIZONA|ARKANSAS|CALIFORNIA|'\
'COLORADO|CONNECTICUT|DELAWARE|FLORIDA|GEORGIA|HAWAII|'\
'IDAHO|ILLINOIS|INDIANA|IOWA|KANSAS|KENTUCKY|'\
'LOUISIANA|MAINE|MARYLAND|MASSACHUSETTS|MICHIGAN|'\
'MINNESOTA|MISSISSIPPI|MISSOURI|MONTANA|'\
'NEBRASKA|NEVADA|NEW\sHAMPSHIRE|NEWSJERSEY|'\
'NEW\sMEXICO|NEW\sYORK|NORTH\sCAROLINA|'\
'NORTH\sDAKOTA|OHIO|OKLAHOMA|OREGON|PENNSYLVANIA|'\
'RHODE\sISLAND|SOUTH\sCAROLINA|SOUTH\sDAKOTA|'\
'TENNESSEE|TEXAS|UTAH|VERMONT|VIRGINIA|'\
'WASHINGTON|WEST\sVIRGINIA|WISCONSIN|WYOMING|USA)'
就是这样!我刚刚使用一些简单的 Python 代码和正则表达式向您展示了通过帐户位置过滤 Twitter 数据的过程。
如果您发现这很有帮助,我鼓励您在自己的工作中扩展这个例子。请随时提出改进建议,或者让我知道这对您是否有帮助。
快乐过滤!
查找并移除数据集中的重复图像
通过自动检测重复和近似重复的图像并删除它们,改进您的深度学习图像数据集
CIFAR-100 中的重复图像在五十一中可视化(图片由作者提供)
最先进的深度学习模型通常在拥有数百万张图片的数据集上进行训练。收集如此规模的数据集本身就是一项非常困难的任务。您可能需要自动化原始数据的处理过程。
一旦您收集了原始数据,您需要确保样本的高质量,以便正确训练和测试您的模型。高质量数据集的一个要求是缺少重复样本。训练集中的副本会导致模型学习 偏向 复制的样本,从而导致模型更难推广到新数据。测试集中的重复将导致对模型的不正确性能评估,从而导致 对不可见数据的更差性能。
在包含数百万张图像的数据集中手动查找重复图像是一项昂贵的工作。编写一个算法来查找完全相同的图像的副本可能很容易,但如果两幅图像只是略有不同,仅因轻微的光照变化或像素值而有所不同,该怎么办呢?这些样本仍然会影响性能,但是很难找到。
本文将向您展示如何自动查找和移除数据集中的重复和近似重复的图像,同时可视化图像以确保移除正确的图像。
我们将查看 CIFAR-100 数据集,我们发现它包含超过 4500 个重复的图像,有时在测试和训练分割之间重复
在这篇文章中,我将使用我正在开发的开源 ML 开发工具 FiftyOne 。它将让您轻松操作和可视化图像数据集,并使用其模型动物园生成数据嵌入。安装非常简单:
pip install fiftyone
Colab 笔记本中来自该博客的代码(图片由作者提供)
概观
- 加载数据集
- 计算嵌入
- 计算相似度
- 可视化并删除重复项
应该注意的是,有多种方式可以做到这一点。此处的示例对于成对查找数据集中每幅图像的近似副本非常有用。
FiftyOne 还提供了一个 [uniqueness](https://voxel51.com/docs/fiftyone/user_guide/brain.html)
函数,该函数计算数据集的标量属性,确定样本相对于其余数据的唯一性。它还可以用于手动查找近似重复,低uniqueness
表示可能重复或近似重复的图像。你可以在文章的最后看到一个例子。
或者,如果你只对精确的副本感兴趣,你可以对你的文件计算一个散列来快速找到匹配。但是,如果图像仅在小像素值上有所不同,这种方法将无法找到副本。
1)加载数据集
第一步是将你的数据集加载到第五十一个中。
在本例中,我将使用图像识别数据集 CIFAR-100 。这个数据集相当旧(2009 年),但仍然足够相关,以至于提交给 ICLR 2021 的论文都在使用它作为基线。
CIFAR-100 包含训练和测试分割之间的 60,000 个图像,用 100 个标签类进行注释,这些标签类被分组为 20 个“超级类”。该数据集也存在于51 数据集 Zoo 中,可以轻松加载。
如果您希望遵循本指南的轻量级版本,您可以加载包含 1000 个样本(或者您指定的任意数量)的数据集子集。
加载的数据集可以在 51 应用程序中可视化。
五十一应用程序中的数据集(图片由作者提供)
1a)加载您自己的数据集
FiftyOne 支持多种标签类型。如果使用分类数据集查找重复项,可以导入一个ImageClassificationDirectoryTree
数据集。
2)生成嵌入
图像在其像素值中存储了大量信息。逐个像素地比较图像将是一种昂贵的操作,并且导致质量差的结果。
相反,我们可以使用预训练的计算机视觉模型来为每个图像生成 嵌入 。嵌入是通过深度模型将图像处理成包含几千个值的向量形式的结果,这些值提取了存储在数百万像素中的信息。
51 模型动物园包含了许多不同的预训练模型,我们可以用它们来完成这个任务。在本例中,我们将使用经过训练的 MobileNet 对 ImageNet 数据集上的图像进行分类。该模型提供了相对较高的性能,但最重要的是它是轻量级的,并且可以比其他模型更快地处理我们的数据集。任何现成的模型都会提供丰富的信息,但人们可以很容易地试验对特定数据集更有用的其他模型。
我们可以轻松地加载模型,并在数据集上计算嵌入。
3)计算相似度
既然我们已经显著降低了图像的维数,我们可以使用经典的相似性算法来计算每个图像嵌入与每个其他图像嵌入的相似程度。
在这种情况下,我们将使用 Scikit Learn 提供的余弦相似度,因为这种算法很简单,并且在高维空间中工作得相当好。
N×N 相似性矩阵为每对 N 个样本提供一个介于 0(低相似性)和 1(相同)之间的值。
[1, 0.532, 0.624, 0.461, ...]
[0.422, 1, 0.125, 0.031, ...]
...
[..., 0.236, 0.942, 0.831, 1]
正如你所看到的,所有的对角线值都是1
,因为每个图像都是相同的。我们可以通过单位矩阵(对角线上为 1,其他地方为 0 的 N×N 矩阵)进行减法,以消除对角线,这样当我们寻找具有最大相似性的样本时,这些值就不会出现。
注 :在超过 100,000 幅图像的数据集上计算余弦相似度会耗费大量时间和内存。建议将嵌入拆分成批,并将该过程并行化,以加快计算速度。
4)可视化并移除重复项
我们现在可以遍历每一个样本,找出哪些其他样本与它最相似。
将结果可视化并按具有最高相似性的样本排序,向我们展示了数据集中的重复项。
按最大相似性图像排序的数据集(按作者排序的图像)
马上,我们可以看到许多重复的东西,甚至更有问题的东西。两个图像是重复的,但一个是在列车分裂和一个是在测试分裂…它们被贴上不同的标签,海豹和水獭!!!这有几个明显的问题:
- 它不可能既是海豹又是水獭,所以其中一个标签是错的。此外,为图像的训练和测试版本提供不同的标签无疑会导致模型失败。
- 包含训练集副本的测试集将导致对模型概化的错误信任。如果测试集没有真正独立于定型集,那么当应用于生产数据时,模型的表观性能可能会下降。
删除重复项
撇开标记和分割的不幸不谈,我们仍然希望自动移除数据集中的重复图像。
通过查看结果,我们可以找到一个阈值,当两个图像被确定为重复时,我们可以使用该阈值作为截止值。该阈值对于该过程中使用的每个数据集/模型都是不同的,因此可视化步骤至关重要。五十一应用程序中的范围滑块提供了一种简单的方法来降低max_similarity
分数,直到我们不再看到重复的分数。
使用滑块查找相似性阈值(图片由作者提供)
看起来好像在 0.94 max_similarity
左右,我们得到的图像是复制的,但通过旋转、翻转和颜色变化得到了增强。数据扩充是一种有价值的工具,可以增加训练数据集的多样性和生产模型的概化能力;然而,如果“原子”训练集中有重复的,那么你的模型的训练时间可能仍然偏向于违规的类,所以我们也想删除近似重复的。
近似重复(图片由作者提供)
进一步的检查将保证重复的良好阈值设定在 0.92 左右。较低的值可能也包括重复值,但应该手动验证,这样我们就不会删除有用的数据。我们也可以通过代码过滤数据集,看看有多少样本的max_similarity
为> 0.92。
60,000 个中有 4,345 个被标记为重复!
现在,我们可以再次遍历我们的数据集,并为每个样本找到所有相似性大于 0.92 的重复项,要么将它们标记为“重复”,要么将其删除。
我们可以找到在训练和测试分割中存在的副本的数量,以及被不同地标记的副本的数量。
结果是 4345 个副本中的 1621 个在训练和测试分裂中,427 个被不同地标记!
(可选)寻找独特的图像
与此相关,FiftyOne 还提供了一种更先进的方法来计算数据集中每个图像的唯一性。这将为每个图像产生一个分数,该分数指示该图像的内容相对于所有其他图像有多独特。“独特性”与“相似性”极性相反。唯一性值较低的图像是您应该探索的潜在副本。
在决定将哪些样本发送给注释者时,惟一性会很有帮助。如果你只打算花钱得到你的数据的最好子集,那么你会想要最独特的样本来训练/测试你的模型。
CIFAR-100 的 2500 个样本子集中最少的独特图像(图片由作者提供)
查找重复的照片和其他文件
基于密码哈希函数的重复查找器
图片来自峡湾
这是同一张照片吗?在另一个文件夹中有这个文件的副本吗?最近我在查阅一些旧文件,不得不经常问自己这些问题。我猜你们大多数人都经历过这样的情况。如您所知,手动识别所有重复文件非常耗时。因此,在这里,我们将探索一种在 Python 中自动识别重复文件的选项。
但是在我们开始&之前,长话短说:如果你只对代码感兴趣,而不是对如何识别重复文件的解释感兴趣,你可以直接进入 Github 库 并开始清理你的系统。否则…我们来看看效果如何。
查找重复文件
我们如何自动化识别重复文件的过程?我们可以生成所有重复文件的列表吗?有几种方法可以做到这一点。所以,我们应该仔细考虑一些选择,然后决定我们想走哪条路。
- 最简单的方法是简单地寻找具有相同名称的文件。但是,如果文件副本是用新名称创建的,我们可能会遗漏重复项。同样,这也很危险,因为同名文件可能包含完全不同的信息。例如:如果你用智能手机拍照,你可能点击了一张名为 IMG_0001.jpg 的图片。然而,我怀疑这是我拿的一样。
- 但是文件大小呢?反对这种方法的理由和反对文件名的理由一样,在这里也适用。更有可能的是,相同大小的文件不会保存相同的内容。
- 好吧,那我们为什么不看看多重特征呢?如果两个文件具有相同的名称、大小和创建日期,它们应该是相同的?是的,他们很可能是相同的,但也有很小的可能不是。此外,我们将再次错过不同名称的重复文件。
所以没有机会可靠地找到我们硬盘上的重复文件?当然有。但它不是基于文件名、大小等参数。相反,我们将直接比较文件的内容。这里最直接的方法是逐位比较两个文件。这将工作,我们将 100%确定文件是对方的副本。然而,根据我们想要检查的文件的大小和数量,对每一个可能的文件对都这样做在计算上是很昂贵的。幸运的是,这里有一个我们可以玩的把戏。我们可以计算每个文件的唯一标识符,然后比较这些标识符而不是整个文件,而不是一点一点地比较所有的东西。检索这种标识符的一种常见方式是加密哈希函数。**
加密哈希函数的概念
在我们进入加密散列函数的概念之前,让我们后退一步,想一想我们希望我们的标识符具有什么特性。
- 标识符必须是唯一的。如果两个不同的文件有相同的标识符,这对我们来说是没有用的。
- 标识符应该是可复制的。我们不希望有随机的标识符,这意味着如果我们再次为同一个文件生成标识符,我们希望得到相同的结果。否则我们不能用它来寻找重复。
对我们来说好的是,我们的两个需求都已经被散列函数满足了。第一个要求被称为防碰撞。这对于任何场景中的每个散列函数来说可能都不正确,但是在我们的上下文中,我们可以假设我们稍后将使用的散列函数是无冲突的。第二个要求是每次计算时为同一个文件生成相同的标识符,这也是散列函数的一般要求——它们是确定性的。此外,哈希函数是单向函数,这意味着给定哈希,不可能重构生成哈希的输入。这一特性开辟了一系列超出本文范围的应用,包括它们在加密货币中的使用,比如比特币。**
加密哈希函数的概念在这里只能粗略地概括,但是解释细节的资源在其他地方是可用的(例如这里的、这里的或者这里的)。简而言之,哈希函数获取不同长度的数据序列,并将它们映射到固定长度的位数组上。由于我们硬盘上的文件大小不一,我们将它们切割成块,然后通过散列函数运行第一块,将中间散列附加到下一块,并通过函数( update )再次运行它。我们这样做,直到处理完所有的块。如果最后一个块比定义的块长度短,将应用填充以确保恒定的块长度。下面的图 1 中也概述了该过程。通常,输入(这里是感兴趣的文件)被称为消息,而哈希函数的输出被称为摘要。
图 1:散列计算的大致轮廓
用 Python 实现
现在我们对加密哈希函数有了一个非常粗略的了解,我们可以继续使用它们来识别硬盘上的重复文件。
如果你想看完整的实现或者直接开始使用,要么去 Github 库 或者用 pip 安装:
**pip install duplicate-finder**
首先,我们需要创建一个函数来计算任何给定文件的哈希。计算将使用 Pythons 的 hashlib 库中包含的 sha256 哈希函数。从下面的代码块可以看出,它遵循了我们在图 1 中描述的内容。首先打开感兴趣的文件,读取固定长度的块,更新摘要,然后从文件中读取下一个块,再次更新摘要,以此类推,直到处理完整个文件。
现在,我们可以将上述函数与另一个函数结合使用,该函数可以搜索感兴趣的目录的所有子文件夹。它将返回每个文件的散列作为一个 Pandas DataFrame ,并且可以选择将搜索限制到具有特定扩展名的文件,例如。jpg 。
由于结果是一个 Pandas 数据帧,我们可以继续使用 Pandas inbuild 方法来查找重复项。结果将再次是一个数据帧,但这一次它只保存重复的文件,按它们的散列排序。此外,我们可以选择将结果导出为。csv 文件。
然而,在某些情况下,我们可能不会对所有的副本感兴趣,而是想知道某个特定文件是否有副本。我们可以使用重复查找器 Python 包来做到这一点,如下所示:
最后,在某些情况下,我们希望比较两个文件夹,并检查重复。这也可以通过我们的重复查找工具包轻松完成:
结论
使用 Python 在文件夹内和文件夹间查找重复文件是一项容易解决的任务。虽然文件名和大小等元数据不适合这项任务,并且逐位比较可能会很慢,但利用加密哈希函数提供了一种有效的前进方式。这里我们使用了 sha256 哈希函数。然而,其他散列算法可以很容易地包含在该框架中。
因此,如果你还没有这样做,你可以查看这篇文章的完整代码这里,在 Twitter 上关注我或者通过 LinkedIn 联系我。
查找缺少的索引:就地
如何在不使用额外空间的情况下找到数组中第一个缺失的整数
作者图片
数据操作算法设计中一个有趣的技术是就地数据操作。这种技术对于节省空间非常有用,在某些情况下这可能是必要的(但是一般不推荐,因为粗心的应用可能导致数据损坏)。
问题是
是这样的:我有一个整数列表,有些是正数,有些是负数。我想找到最小的缺失索引。
这意味着给定一个包含 3 个数字的列表:[-1,1,0],它们的索引是[1,2,3]。哪个是最小的缺失指数?那就是两个。
再比如:[4,5,6]。它们的指数是[1,2,3],现在最小的缺失指数是 1。
解决方案 1:设置
最简单的解决方案是使用一个集合结构来存储找到的整数,然后遍历每个索引来找到第一个丢失的整数:
def get_missing_min0001(inputs):
input_set = set()
input_max = None
for input in inputs:
input_set.add(input)
input_max = max(input, input_max) \
if input_max is not None \
else input
i = 1
while i in input_set and i < input_max:
i = i + 1
return i if i != input_max else None inputs = [1, 3, 2, 6]
expected = 4
assert get_missing_min0001(inputs) == expected
- 时间复杂度
因为我们遍历数组中的每个元素一次,所以时间复杂度是 O(N ),其中 N 是输入元素的数量。集合结构和字典一样,具有 O(1)的查找和插入复杂度。
- 空间复杂度
我们需要将元素存储在一个集合中,这需要 O(N)空间。
解决方案 2:就地
时间复杂度看起来是最优的,空间复杂度也不错,还有什么可以优化的呢?在现实生活的应用程序中,这可能是你能做的最好的事情(也可能是应该做的)。但是实际上有一种方法可以进一步优化这个解决方案的空间复杂度。
注意输入本身是一个数据结构(确切地说,是一个大小为 N 的列表)?如果我们可以利用它来替代我们用来存储 seen 索引的集合,那么我们就不需要分配额外的空间。
一个简单的方法是,对于我们在列表中遇到的每个整数,我们将该索引处数字的符号变为负数,例如:
我们从以下内容开始:
[1, 3, 2, 6]
我们遇到的第一个数字是 1,因此我们将索引 1 处的数字变为负数:
[-1, 3, 2, 6]
第二个数字是 3,因此我们将索引 3 处的数字变为负数:
[-1, 3, -2, 6]
第三个数字是 2(取绝对值):
[-1, -3, -2, 6]
第四个数字是 6,它超出了数组的长度,所以什么也不做。
最后我们得到[-1,-3,-2,6],再看一遍这些数字,我们发现最小的正数索引是索引 4,这就是我们的答案。
输入数据包含负数怎么办?如果有零呢?对于负数或零,我们可以用 1 代替它们,因为第一个索引是 1。当然,我们需要做一个检查,以确保列表中存在 1。如果不是,那么答案就是 1。
解决方案如下:
def get_missing_min0002(nums):
has_one = False
for i in range(len(nums)):
# check that 1 exists
if nums[i] == 1:
has_one = True
# convert < 1 to 1
if nums[i] < 1 or nums[i] > len(nums):
nums[i] = 1
if not has_one:
return 1
for i in range(len(nums)):
nums[abs(nums[i]) - 1] = - abs(nums[abs(nums[i]) - 1])
for i in range(len(nums)):
if nums[i] > 0:
return i + 1
return len(nums) + 1
- 时间复杂度
我们对每个数字循环两次,因此运行时间复杂度是 O(N)。
- 空间复杂度
输入数据用于存储索引信息,没有额外分配内存,所以空间复杂度为 O(1)。
解决方案 3:就地递归
用负数做集合指标是不是有点 hacky?是的,是的,我同意。
理想情况下,我们更喜欢一个明确的指标,不依赖于特殊的含义,如“无”。但是有一个实际的困难,如果我们把一个索引上的数字设置为 0,那么我们就丢失了那个索引上的信息。使用前面的例子:
我们从以下内容开始:
[1, 3, 2, 6]
我们遇到的第一个数字是 1,因此我们将索引 1 设置为“无”:
[无,3,2,6]
我们遇到的第二个数字是 3,因此我们将索引 3 设置为“无”:
[无,3,无,6]
但是等等!
既然我们已经将索引 3 设置为 None,我们就不再知道索引 3 的数字是多少了。
在这种情况下,我们需要的是递归。
当我们在索引 2 处遇到 3 时,我们检查并意识到在索引 2 处找到的数字不是 2,所以我们首先将数字保存在索引 3 处(将 2 保存到一个变量),将索引 3 设置为“无”,并递归地遍历索引 2,最终我们在索引 2 处找到 3,由于索引 3 已经是“无”,我们只需要将索引 2 设置为“无”,我们就都设置好了:
[无,无,无,6]
我们遇到的最后一个数字是 6,这又一次超出了索引,所以我们什么也不做,最后的结果是缺少的索引是 4。
def get_missing_min0003(nums):
for i in range(len(nums)):
nums[i] = nums[i] - 1
# recursive reduction function
def _reduce_inputs(inputs, i):
if i is None:
return
if i < 0:
return
if i >= len(inputs):
return
r = inputs[i]
inputs[i] = None
if r is None or r == i:
return
_reduce_inputs(inputs, r)
for i in range(len(nums)):
_reduce_inputs(nums, nums[i])
for idx, i in enumerate(nums):
if i is not None:
return idx + 1
return len(nums) + 1
- 时间复杂度
O(N)
- 空间复杂度
O(1)
就这样,问题优雅地解决了。(我也想使用队列,但这会增加内存使用……)
结论
尽管就地内存操作很酷、很有趣并且节省空间,但它不是最健壮的编程技术。如果函数的用户希望输入保持不变,以便用于其他目的,该怎么办?修改输入的 API 不是一个好主意。
权力越大,责任越大。
(递归解决方案有一个问题,如果你想通了,请告诉我!)
毫不费力地找到最匹配的数据分布
如何以自动化和简单的方式为您的数据点找到最匹配的统计分布。然后,如何进一步扩展该工具。
我们的目标是什么?
图片来源:作者用 Pixabay 图片制作(免费使用)
你有一些数据点。最好是数字。
你想找出它们可能来自于的哪个统计分布。经典的统计推断问题。
当然,有严格的统计方法来实现这个目标。但是,也许你是一个忙碌的数据科学家。或者,一个更忙的软件工程师碰巧得到了这个数据集来快速编写一个应用程序端点,以找到与数据匹配的最佳分布。以便另一个机器学习应用程序可以使用基于这种分布生成的一些合成数据。
简而言之,您手头没有很多时间,并且想要找到一个快速方法来发现数据可能来自的最佳匹配分布。
基本上,您想要在许多发行版上运行自动批次的 拟合优度(GOF)测试 ,并快速总结结果。
当然,您可以从头开始编写代码,使用比如说 Scipy 库,一个接一个地为许多发行版运行标准的 GOF 测试。
或者,您可以使用这个 小而有用的 Python 库 — distfit 来为您完成繁重的工作。
distfit——一个 Python 库,用于自动将分布与数据相匹配
根据他们的网站 , **distfit**
是一个 python 包,用于单变量分布的概率密度拟合。它使用残差平方和(RSS)和 GOF 的其他度量来确定 89 个理论分布的最佳拟合。
让我们看看如何使用它。这里是 演示笔记本 。
照常安装,
pip install -U distfit
生成测试数据并进行拟合
生成一些正态分布的测试数据,并将它们拟合到 distfit 对象。
基本上,您希望在许多发行版上运行自动化的一批拟合优度(GOF)测试,并快速总结结果
合身程度如何?
那么,合身吗?
注意,在上面的代码中,模型dist1
不知道生成分布或其参数,即正态分布的loc
或scale
参数,也不知道我们调用np.random.normal
来生成数据的事实。
我们可以通过一段简单的代码一次性测试拟合优度和估计的参数,
dist1.plot(verbose=1)
这是预期的曲线图(注意,由于生成数据的随机性,在您的情况下,曲线图看起来肯定会有些不同)。
注意 **loc**
和 **scale**
参数是由绘图副标题中的拟合过程估计的。非常接近我们之前设置的参数值,不是吗?估计的分布类型显示为norm
,即正态分布。好极了。
作者创作的图像
关于合身模型的更多信息
使用另一个一行代码,您可以获得所有符合数据(内部)并经过拟合优度测试的分布的摘要。
dist1.summary
你会得到这样的东西,
作者创造的形象
这显示了用给定数据测试的各种分布的所有参数。它还显示了**score**
,表示拟合优度 —预期数据和给定数据之间的距离,即越低越好。请注意,在此模型中,不止一个分布具有相同的零分,但正态分布被选为内部逻辑下最合理的分布。
为什么这个摘要中只有 10 个分布?因为默认情况下,它使用最流行的 10 个发行版的列表进行扫描。在初始化时,您可以将确切的列表指定为distfit
对象的参数。
在内部使用 Scipy
如果您键入dist1.distributions
,那么您将看到拟合过程中使用的函数列表,它们来自 Scipy 包。
不要停留在拟合上,还要生成合成数据
作为一个附加组件,distfit
model 提供了基于最佳拟合分布轻松生成数据的 API。这里,我们用loc=5.5
和scale=9.79
生成 10 个随机变量(如之前拟合的)。
你必须小心的事情
如果两个或多个分布的数据形状之间有很多相似之处,则估计可能是错误的。特别是,如果样本量(训练数据)很小。
例如,让我们从 Beta 分布 中生成一些数据,选择参数,例如它们看起来几乎像正态分布。如果我们选择参数 α 和 β 相等或接近,我们可以实现这一点。然后,如果你拟合 1000 个数据点,你可能得到正态分布作为最佳拟合分布。
作者创作的图像
然而,如果你把样本量扩大到 10,000 点,你很可能会得到正确的答案。
作者创造的形象
你可以做的其他事情
可以选择哪个统计检验 (RSS,Kolmogorov-Smirnov 等。)用于确定最佳拟合。
您还可以指定您想要运行的发行版的精确列表。
你可以使用distfit.predict
方法预测一个响应变量的概率。
我们只展示了连续分布拟合的例子。你也可以用离散分布进行拟合。
为什么这是一个“生产数据科学”的例子?
我认为使用像distfit
这样的实用程序包是进行 高效数据科学 的一个典型例子。
我在这篇文章中写过什么是生产数据科学。本质上,这意味着以更高的速度、稳健的方式进行同样的数据科学活动。
您可以使用 Scipy 函数从头开始编写纯 Python 代码,遍历各种发行版,并对您拥有的数据运行 GOF 测试。但是当有人已经为完全相同的任务编写了一个优秀的库(带有高质量的文档)时,你为什么还要浪费时间呢?
这就是为什么每当您想要将单变量数据拟合到最佳分布并一次性获得所有统计属性时,您都可以想到distfit
。
Y 你可以查看作者的 GitHub 知识库获取机器学习和数据科学方面的代码、思想和资源。如果你和我一样,对人工智能/机器学习/数据科学充满热情,请随时在 LinkedIn 上添加我或在 Twitter 上关注我。
https://www.linkedin.com/in/tirthajyoti-sarkar-2127aa7/
享受中等:https://medium.com/@tirthajyoti/membership
Python 中的“寻找差异”
difflib——Python 内置库中隐藏的瑰宝
最近,我一直专注于审查和试用 Python 内置库。这个自我分配的任务给我带来了很多乐趣。Python 中有许多有趣的特性,为不同类型的问题提供了现成的实现和解决方案。
其中一个例子就是我要在本文中介绍的内置库——Difflib。因为它是 Python3 内置的,所以我们不需要下载或安装任何东西,只需如下导入即可。
import difflib as dl
现在我们应该开始了:)
1.查找“已更改”的元素
我相信我的大多数观众都知道如何使用 git。如果您是其中之一,您可能已经看到了如下带有冲突的原始代码文件。
<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
在大多数 Git 的 GUI 工具中,比如 Atlassian Sourcetree,您一定见过这样的表示。
图片提供:https://blog.sourcetreeapp.com/files/2013/03/hero-small.png
减号表示该行代码在新版本中被删除,而加号表示该行代码被添加到新版本的代码中,而该代码在旧版本中并不存在。
在 Python 中,我们可以使用 Difflib 通过一行代码轻松实现非常类似的东西。我要展示的第一个函数是context_diff()
。
让我们用一些字符串元素组成两个列表。
s1 = ['Python', 'Java', 'C++', 'PHP']
s2 = ['Python', 'JavaScript', 'C', 'PHP']
然后,魔法来了。我们可以生成如下的比较“报告”。
dl.context_diff(s1, s2)
context_diff()
函数将返回一个 Python 生成器。因此,我们可以循环它来一次性打印所有内容。
for diff in dl.context_diff(s1, s2):
print(diff)
输出使用感叹号!
清楚地显示第二个和第三个元素是不同的,表示“这个元素是不同的”!
在这种情况下,第一个和第四个元素是相同的,因此它将只显示差异。最有趣的是,如果我们把场景变得更复杂,它会显示出更有用的东西。让我们将这两个列表更改如下。
s1 = ['Python', 'Java', 'C++', 'PHP']
s2 = ['Python', 'Java', 'PHP', 'Swift']
上面的输出表明“C++”已经从第一个列表(原始列表)中删除,“Swift”已经被添加到第二个列表(新列表)中。
如果我们想显示与从 Sourcetree 获得的截图完全相似的内容,该怎么办?是的,Python 允许我们这样做。只需使用另一个名为unified_diff()
的函数。
dl.unified_diff(s1, s2)
unified_diff()
函数将两个列表“统一”在一起,可以生成如上图所示的输出,在我看来这更具可读性。
2.准确指出差异
照片由 Pixabay 上的 lucasgeorgewendt 拍摄
在第 1 节中,我们着重于确定行级的差异。能不能具体一点?例如,如果我们想要一个字符一个字符地比较,并显示有什么不同呢?
答案是肯定的。我们可以使用ndiff()
功能。
假设我们正在比较两个列表中的单词,如下所示。
['tree', 'house', 'landing']
['tree', 'horse', 'lending']
这三个单词看起来非常相似,但是只有第二和第三个单词有一个字母的变化。让我们看看函数会返回给我们什么。
它不仅显示了哪些内容已更改(带减号和加号)和未更改(“树”未更改,因此根本没有指示符),还显示了哪个字母已更改。^
指示符已正确添加到已被识别为差异的信函中。
3.获得相近的匹配
你有没有输入“teh”被自动更正为“the”的经历?我打赌你有,我一直都是这样:)
现在,有了 Difflib,您可以非常容易地在 Python 应用程序中实现这个特性。关键是使用get_close_matches()
功能。
假设我们有一个候选列表和一个“输入”,这个函数可以帮助我们挑选与“输入”接近的一个(或多个)。让我们看看下面的例子。
dl.get_close_matches('thme', ['them', 'that', 'this'])
当我们输入“thme”(一个错别字)而不是“this”或“that”时,它成功地找到了“them”,因为“them”是最接近的一个。但是,该函数不能保证返回某个值。也就是说,当没有足够接近输入的内容时,将返回一个空列表。
这非常有意义,因为我们不会一直犯拼写错误,对吗?😃
事实上,我们可以通过向参数cutoff
传递一个参数来控制如何度量“相似性”。它需要一个介于 0 和 1 之间的浮点数。数字越大意味着越严格,反之亦然。
一个cutoff = 0.1
足够小,可以让函数匹配输入的所有候选项。如果我们想限制返回的匹配项的数量呢?我们可以使用另一个参数n
,它将返回给我们“前 n 个”最匹配的术语。
4.如何将一个字符串 A 修改为 B?
如果你有一些信息检索的知识,你可能已经意识到上述函数利用了 Levenshtein 距离。它试图找出两个文本术语之间的差异,并测量它们之间的“距离”。
通常,该距离由修改术语 A 到 b 所需的最小替换、插入和删除次数来定义。有时,不同的修改将被赋予不同的权重。在本文中,我将跳过算法部分。如果你感兴趣的话,可以去 Levenshtein Distance 的 Wiki 页面了解详情。
其实这篇文章还没写完。使用 Difflib,我们甚至可以实现如何将 Levenshtein 距离应用于两个字符串的步骤。这可以使用 Difflib 中的SequenceMatcher
类来完成。
假设我们有两个字符串abcde
和fabdc
,我们想知道如何将前者修改成后者。第一步是实例化该类。
s1 = 'abcde'
s2 = 'fabdc'seq_matcher = dl.SequenceMatcher(None, s1, s2)
然后,我们可以使用类方法get_opcodes()
来获得元组列表,该列表指示:
- 修改操作(插入、等于或删除)的标签
- 源字符串的开始和结束位置
- 目标字符串的开始和结束位置
我们可以将上述信息“翻译”成可读性更强的东西。
for tag, i1, i2, j1, j2 in seq_matcher.get_opcodes():
print(f'{tag:7} s1[{i1}:{i2}] --> s2[{j1}:{j2}] {s1[i1:i2]!r:>6} --> {s2[j1:j2]!r}')
超级爽:)
你可能也注意到了,我们传递给SequenceMatcher
类的第一个参数是None
。此参数用于指示某些字符可能被“忽略”的算法。这种忽略并不意味着从源字符串中删除它,而是在算法处理中忽略它。我知道这有点难以理解。让我给你看一个例子。
seq_matcher = dl.SequenceMatcher(lambda c: c in 'abc', s1, s2)
字母“abc”不会在算法中运行,但会被视为一个整体。
最后但同样重要的是,下面的例子展示了我们在实践中如何使用这个函数。
摘要
在本文中,我介绍了另一个名为 Difflib 的 Python 内置库。它可以生成报告,指出两个列表或两个字符串之间的差异。此外,它还可以帮助我们在输入和候选字符串列表之间找到最匹配的字符串。最终,我们可以使用这个模块的一个类来实现一些更复杂和高级的功能。
https://medium.com/@qiuyujx/membership
如果你觉得我的文章有帮助,请考虑加入灵媒会员来支持我和成千上万的其他作家!(点击上面的链接)
找到你公司的知识中心
在冗余数据上使用社会网络分析
来源:unsplash.com,图片作者:
奥斯丁·迪斯特尔
一场非常普通的斗争
假设你是一家快速发展的大公司的新经理,你需要问题的答案。你怎么知道如何提问?
虽然团队像蘑菇一样到处涌现,每个奇数周都会改变方向,但你真的不能再依赖过时的组织图表了。你最好自己去发现内部网络,找到最有价值的贡献者。
这就是社会网络分析(SNA)可以发挥作用的地方。
不过,在进入网络科学之前,我建议先浏览几个基本概念,以便熟悉这个主题:
- 网络科学:尼基·凯斯(Nicky Case)的一款名为《群体的智慧与疯狂》(T9)的互动游戏。
- 社交网络分析:由 Mitchell Telatnik 撰写的简短 medium pos t。
我们可以使用来自 Slack 等通信系统的数据,用 Python 构建网络。这些人通过他们发送的信息联系在一起,我们可以通过下载聊天记录来跟踪他们。
目标
…就是找到:
- 谁在网络中拥有最多的连接=谁发送/接收的消息最多?
- 谁在网络中连接最多和最少的部分(离群值)之间充当桥梁=谁对信息流的影响最大?
数据
今年早些时候,我参加了一个数据分析训练营,获得了一个相对较小但真实的数据集,这个训练营有 3 个月的价值。
使该数据集适合分析需要一些时间,但所有步骤都包含在 EDA 笔记本中。为了可视化网络,我使用了 Python 的 Network X 库——代码可以在名为 network_graphs 的文件中找到。
为了消除我的第一个概念验证的噪音,我只查看了公共频道上的一对一对话(两个人之间的线索)。这似乎是一个明智的选择,因为我自己也是网络科学的新手。
让我们找到那些枢纽!
大约
- 30 小时的争吵
- 2 社交网络分析课程(Datacamp 和 Coursera,好久不见!)
- 几个心理障碍之后,我发现自己对我的第一张图表感到困惑和惊讶:
啊哈!我想,这究竟是怎么回事。我可以把消息看作是用户之间的联系,但是必须找到一种方法把这些用户 id 变成真实的名字。
在更多的数据争论之后,我用一个圆形布局的有向图来清楚地显示谁给谁发了信息。
看起来不错。我们现在可以清楚地看到信息的方向,所有的名字都是有意义的。你能猜出谁的关系网最广吗?
回到我们的主要目标,我们需要找到与更孤立的个人有良好联系的用户,以了解:
- 谁知道网络中发生的最微小的事情,
- 谁能把信息传播到各处。
它们被称为具有最高介数的节点。如果你越来越难以理解,现在是查看文章开头提到的资源的好时机。
用蓝色突出显示:Sian D、Sam K 和 Thamo K 似乎是您的主要联系点。
好吧,假设你运气不好,那三个人此刻正在桑给巴尔啜饮冰镇果汁朗姆酒,所以我们需要下一对排队的人。
下图显示了以下特征:
- 十个联系最紧密的人,我们的问题突出显示为较大的节点和
- 三个黄色的连接到网络的隔离部分。
看这张图,还有几件事要提一下。
你看到那些黄色的圆圈和它们之间的联系了吗?分析师表示,它们就像网络中的桥梁,因此很容易变成瓶颈,因为它们可以在保存和传播信息方面发挥核心作用。
连接最少的个体是网络的离群者,他们坐在边缘,没有太多的连接(有意或无意)。如果他们聚集在一起,形成孤岛,他们可能会损害公司的生产力和效率,因为他们将与中心行动脱节,并可能偏离轨道。
谈到生产率,作为一名曾经帮助公司找到并消除高绩效障碍的前顾问,我对这一部分特别感兴趣。我发现了 SNA 中一个处理公司网络的特殊领域,称为组织网络分析,它提供了关于公司内部工作的新鲜和可行的见解,例如人们如何在团队中合作,以及谁是推动公司内部变革的关键影响者。
好吧,我觉得是时候承认了:ONA 是我做这个项目的原因。我发现发现一个组织每天挣扎的真正原因,而不是靠猜测来玩,这很有意思。
准备好自己尝试了吗?
以这个回购为基础,拿自己团队的 Slack 数据,看看谁是你公司最有人脉/最有价值的用户。
请注意,这些指标只能让你起步,明智地使用它们,并用常识验证。
特别感谢
Eric Sims 在 DataTalks 上的演讲鼓励我继续这个项目,我的兄弟 Mark Szulyovszky 和我的 python 导师 James Clare 帮助我度过了陷入困境的阶段。
这是所有的乡亲。
通过可视化频率分布找到数据集的模式(Stat-05)
入门
通过可视化频率分布来深入了解数据集
视觉化给你一些你不知道的问题的答案— 本·施奈德曼
数据科学被定义为解释数据并从中获取有用信息的艺术。同时,数据可视化涉及到数据的表示。尽管它们来自完全不同的实体,但背景是相同的。数据科学不是单一的流程、方法或工作流。我们可以认为数据可视化是数据科学的子集。
数据科学在我们日常生活中的最好例子是用户购物时的电子商务推荐。机器定期学习用户的活动,并根据你的兴趣和购物选择来操纵它,从而给出最佳建议。分析原始数据非常困难。数据科学家需要将操纵的数据可视化并进行分析,以便为用户提供最佳选择。这就是数据可视化发挥作用的地方。
有几种统计和数学方法,我们可以通过这些方法获得关于数据集的洞察信息。其中,频率分配是最简单但也是最重要的技术。
路线图…
- 为什么需要频率分布的图形表示?
- 频率分布柱状图
- 频率分布饼图
- 频率分布直方图
- 偏斜频率分布
- 频率的对称分布
让我们开始我们的旅程……
什么是数据可视化?
数据可视化是将信息转换成可视化上下文(如地图或图形)的实践,以使数据更容易被人脑理解并从中获得见解。数据可视化的主要目标是从数据中发现模式。数据可视化是数据科学的一部分。收集数据后,我们必须修改和模拟数据。最后,它应该是可视化的最终结论。
为什么需要频率分布的图形表示??
要深入理解它,你必须有频率分布的先验知识。要知道什么是频数分布,如何制定频数分布表。可以看我们之前的文章基于频率分布。
在我们以前的文章中,我们可能会看到如何从原始数据创建一个频率分布表。当我们试图从数据中寻找模式时,我们可能会面临另一个问题。你猜怎么分析频率表从数据集中找到模式?如果您想从频率表中找到一个模式,您必须查找每个唯一值或类间隔的频率。仅仅通过查找每个唯一值的频率,就能发现什么规律吗?不,你必须同时比较每个值的频率。对于一些独特的值或类间隔,或者当频率值较少且更容易比较时,这将是容易的。但是,如果我们试图比较大量唯一值的频率,我们会感到困惑。我们可以通过可视化数据来解决这个问题。图表使扫描和比较频率变得容易得多,提供了整个变量分布的单一图像。因为它们容易掌握,也引人注目。有时,您必须在非技术人员面前展示数据。如果我们需要向非技术观众展示我们的发现,图表是更好的表达方式。在本文中,我们将讨论三种表示分布表的图形:
1。条形地块
2。饼状图
3。直方图
- 我们正在考虑一个数据集,以便更好地演示
在本文中,我们使用的是 wnba.csv 数据集。全国女子篮球协会 ( WNBA )是美国的职业篮球联盟。它目前由 12 个小组组成。在我们的数据集中,我们有 2016-2017 赛季所有比赛的统计数据。数据集有 143 行和 32 列。数据集概述如下。
频率分布柱状图
条形图或条形图是一种图形,用矩形条表示数据类别,矩形条的长度和高度与它们所表示的值成比例。
柱状图用于在序数或名义尺度上测量的变量。显示 1801-1961 年间 Edge 人口变化的条形图示例。
作者照片
- 如何生成柱状图
要生成条形图,我们需要两组值。
(I)一个包含唯一值列表的集合。
(ii)另一组包含每个独特值的频率。
我们可以很容易地从频率表中得到两组数值。为了得到一个频率表,我们可以使用 pandas Series.value_counts()
方法。那我们就得用Series. plot.bar()
的方法。我们可以对数据集中的Pos (Player Position)
变量这样做。
我们可以使用Series.value_counts().plot.bar()
只用一行代码创建柱状图。
wnba[‘Pos’].value_counts().plot.bar()
输出:
作者照片
Series. lot.bar()
方法生成竖条印迹,其中频率在 y 轴,每个唯一值在 x 轴。有时,您需要生成一个水平条形图。要生成水平条形图,您可以使用Series.plot.barh()
方法。
wnba[‘Pos’].value_counts().plot.barh()
输出:
作者照片
- 如何自定义条形图
Series.value_counts().plot.bar()
方法有几个参数。
(i)x-设置 x 轴的标签。
(ii)y-设置 y 轴的标签。
(iii)颜色-设置自定义颜色。
(iv)旋转-旋转 x 轴的技巧标签。
(五)以此类推。
通过更改这些参数,您可以根据需要装饰您的条形图。
欲知详情,可以阅读 柱状图 的文档。
频率分布饼图
饼图是一种以圆形图形直观显示数据的图表。数据的圆形、球形和角形表示通常是用来表示真实世界数据的图形。饼图的形状是圆形的,其中饼图代表整个数据,饼图的切片代表数据的各个部分,并离散地记录数据。
它可以假设为一个普通的馅饼。让我们看看下面的例子,它代表了制作奶油蛋糕所用的配料。
作者照片
整个饼图代表值 100。各种颜色代表了制作蛋糕的原料。只看切片颜色就能理解除法。
- 我们为什么要用饼状图?
饼图相对于条形图的主要优势在于,它能更好地显示分布中的相对频率,或者说是比例频率。查看条形图,我们可以看到哪些类别的数量或多或少,但我们无法判断比例。
只看饼状图,就能论证出各个品类的比例。
- 如何生成饼状图
我们可以使用Series.plot.pie()
方法生成饼图。我们可以在数据集中的‘Pos’
列上应用该方法。
`wnba[‘Pos’].value_counts().plot.pie()
输出:
- 如何自定义饼状图
在大多数情况下,我们希望每个切片的百分比应该显示在切片内部。我们可以通过设置auto pct参数来轻松实现。该参数接受 python 字符串,我们可以使用 '%.1f%%' 以一位小数的精度显示百分比。在下面,我们分解琴弦。
作者照片
我们可以在下面展示它如何寻找精度值为 2 的‘Pos’
变量。
wnba[‘Pos’].value_counts().plot.pie(figsize = (6,6), autopct = ‘%.2f%%’)
输出:
为频率分布直方图
频率分布显示一组数据中每个不同值出现的频率。直方图是最广泛使用的可视化频率分布的技术。它看起来像一个条形图,但有明显的区别。
- 我们为什么要用直方图?
当在区间和比例范围内测量变量属性时,详细描述分布。让我们用一个真实的例子来理解这个事实。
让我们使用‘PTS’ (total points )
,它是在比率标尺上测量的。
print(wnba[‘PTS’].describe())
输出:
作者照片
如果我们试图分析上面的图表,我们会发现 75%的变量分布在一个相对狭窄的区间内。剩下的 25%分布在相对较大的区间内。为了形象化这一事实,我们必须画一张图来立即显示分布情况。
- 如何生成直方图
我们可以使用Series.plot.hist()
方法生成一个直方图。我们可以在数据集中的‘PTS’(total points)
列上应用该方法。
wnba[‘PTS’].plot.hist()
输出:
作者照片
- 如何自定义直方图
有时候,你必须创建一个固定数量的条,比如 2,5,10,20,30。如果您想在直方图中为一个‘PTS’
变量创建 5 个条形,幕后会发生什么?以下步骤将有助于您的工作。
(I)为具有 5 个类别间隔的‘PTS’
变量生成分组频率分布表。
(ii)对于每个课堂间隔,绘制一个高度与间隔频率相对应的条形图。
print(wnba[‘PTS’].value_counts(bins = 5).sort_index())
输出:
作者照片
这里,箱参数表示类间隔的数量。
现在,我们尝试借助直方图来表示数据。
wnba[‘PTS’].plot.hist(bins=5)
输出:
作者照片
您还可以使用 numpy 的arange()
函数来生成用于绘制特定范围和间隔的频率的值,使用网格参数来清楚地理解条形,使用 rot 参数来获得更好的可读性。
from numpy import arange
wnba[‘PTS’].plot.hist(grid = True, xticks = arange(2,585,58.2), rot = 30)
输出:
作者照片
如果你分析图表,你可以找到你想要看到的模式。我们可以看到,75%的值在 2–277 之间,其余的值分布在 277–584 之间。所以图是偏左的(偏态分布),我们会在文章的字母部分了解一下。
偏斜频率分布
偏斜分布是一条尾巴比另一条长。这些分布有时被称为不对称或不对称分布。两种类型的偏态分布
(一) 右偏分布
如果尾部指向右侧,则称分布为右偏。
(二) 左偏分布
如果尾部指向左侧,则称分布为左偏。
作者照片
对称分布
当均值两边的分布是另一边的镜像时,称该分布是对称的。
一种非常常见的对称分布是直方图中间值高,频率向两端逐渐降低。这种模式也称为正态分布。
作者照片
结论
在整篇文章中,我们试图了解可视化频率分布的技术。然而,当变量以名义或顺序尺度来衡量时,我们应该使用条形图或饼图。但是,如果变量是在一个区间或比率尺度上测量的,那么我们必须使用直方图。
如果你是数据科学爱好者,请与我保持联系。我很快会带着另一篇有趣的文章回来。如果你喜欢这篇文章,别忘了加上一些掌声。
数据科学统计系列文章
- 少即是多;采样的‘艺术’(Stat-01)
- 熟悉数据科学最重要的武器~变量(Stat-02)
- 要提高数据分析能力,您必须了解频率分布(Stat-03)
- 通过可视化频率分布找到数据集的模式(Stat-04)
- 比较多个频率分布,从数据集中提取有价值的信息(Stat-05)
- 通过简短的讨论消除你对均值的误解(Stat-06)
- https://medium.datadriveninvestor.com/increase-your-data-science-model-efficiency-with-normalization-918484b4626f?source=your_stories_page-------------------------------------
- 数据科学基础概率概念(Stat-08)
- 从朴素贝叶斯定理到朴素贝叶斯分类器的路线图(Stat-09)
- 数据科学爱好者需要了解的假设检验(Stat-10)
- 用 ANOVA 进行多组间的统计比较(Stat-11)
- 用卡方检验比较分类变量的依赖性(Stat-12)
使用 Tableau 每月查找热门产品
如何使用详细程度计算来选择和显示每月增加最多的销售额
假设您销售大量产品,并希望了解哪些产品的销售额增长最快。在 Tableau 中使用快速表格计算很容易做到这一点:计算差额,按大小排序,去掉除最大数字以外的所有内容。但是,如果您想要一个每月自动完成这项工作的仪表板,该怎么办呢?
作者使用照片提供图片(左)安娜·邦达伦科在像素上的照片 |(右)卢卡斯在像素上的照片
最近有人要求我这么做,但我找不到任何讨论类似问题的文章,所以想分享我用来创造观想的解决方案。在本文中,我将创建一个图表,自动选择上个月销售额增长最大的五种产品,并可视化这种变化。这是写给以前做过 Tableau 的人的,定位在初级/中级水平。
我不会分享我的完整玩具数据集,但我已经包括了下面的前几行给你一个想法。它包括每个销售的一行,带有日期/日期时间和产品字段。自然,真实的销售数据集将包含更多的信息,但这对我们的目的来说已经足够了。
+---------+---------------+
| Product | Purchase Date |
+---------+---------------+
| Glass | 23/08/21 |
| Mug | 02/07/21 |
| Plants | 31/08/21 |
| Rug | 04/09/21 |
+---------+---------------+
一旦将 Tableau 连接到数据,就可以开始将正在使用的日期字段拖放到列中,将产品字段拖放到行中,将记录数拖放到文本标记中。您可能需要编辑列中的日期药丸以显示连续的月份。
(图片作者)
这种数据的表格视图可能有助于向用户展示其本身,但也有助于验证您的计算。虽然我使用的是平面文件,但我模拟了一个包含九月份部分数据的实时数据连接。本文假设,因为这只是部分数据,所以还不感兴趣,并着眼于 7 月和 8 月之间的变化。
创建一个新的工作表来计算和显示每月的变化。为了计算上一个整月与其前一个整月之间的差异,我们需要创建一个计算字段。特别是详细程度的计算。Tableau 对它们有很好的解释这里是,但是本质上它们允许你在不同的细节层次上计算值。在这种情况下,我们希望了解每个产品的变化,因此我们希望在产品级别进行计算。如下所示创建计算字段。
//calculates change in sales per product between last two months
{fixed [Product]:
COUNT(IIF(DATEDIFF('month',[Purchase Date],TODAY())=1,
[Product],NULL)) -
COUNT(IIF(DATEDIFF('month',[Purchase Date],TODAY())=2,
[Product],NULL))
注意这个函数中注释的使用;对于像这样的长时间计算,这些总是可取的。此计算将计算上个月和上个月购买日期的行数之间的差异,所有这些都是按产品计算的。通过要求 Datediff 函数等于 1,可以从当前月份中筛选出任何值。
创建该字段并将其命名为“销售额变化”之后,您可以创建一个如下图所示的图表。在这个阶段,您可以根据表 1 中的表格验证 LOD 计算的变化值。
(图片作者)
下一步是让 Tableau 选择销售变化最大的产品。在维中,右键单击产品字段,然后选择创建>设置。在弹出窗口中,选择顶部选项卡,选择“按字段”并使用您创建的 LOD 计算作为选择依据的变量,确保聚合设置为 Sum。在本例中,我们选择了查看前 5 名。
(图片作者)
一旦您创建了这个集合,进入过滤器并选择。这应该会过滤掉前两个月中销售额变化最大的五种产品。因为用于创建动态集的 LOD 计算是用来查找与今天的日期相比最近的月份的,所以这前 5 个将每月更新一次。
(图片作者)
当然,这是一个非常简单的例子和一个非常简单的图表,但它展示了这些销售趋势计算的能力。这方面的一些细微变化包括希望看到销售额下降最多的产品(使用上面的方法实现,但在创建集合时在“按字段”选项中选择底部而不是顶部),或者希望看到总体变化最大的产品(在用于创建集合的 LOD 计算周围添加 ABS()函数,但在显示值时使用与上面相同的计算)。
为了给图表添加一些更加用户友好的功能,我们可以为用户提供他们想要看到多少趋势产品的选项。为此,在创建集合时,单击下拉菜单 5,选择“创建新参数”并创建一个名为“产品数量”的参数。确保参数设置为显示参数控制。
(图片作者)
我们还可以使用参数的力量来允许用户选择他们是看到表现最好的产品还是表现最差的产品。为此,首先创建两个集合,一个选择排名靠前的产品(例如“排名靠前的产品”),另一个选择排名靠后的产品(排名靠后的产品)。然后,我们创建一个数据类型为 String 的参数,并赋予它两个可能的值“Trending”和“Decreasing”。
(图片作者)
然后创建一个使用 CASE()的计算字段,以允许参数选择来确定使用哪个集合。按照下面的代码块创建该字段,将该字段转换为维度,将其作为唯一的筛选器添加到工作表中,并在出现提示时选择 1。
//toggles which set to apply based on parameter selection
CASE [Trending or Decreasing Toggle]
WHEN 'Trending' THEN INT([Top Trending Products])
WHEN 'Decreasing' THEN INT([Top Decreasing Products])
END
您可能需要编辑视觉效果的标题,以包含正在使用的参数。特别是如果你允许用户选择他们看到的是增加还是减少的销售,有一个非反应性的标题可能会令人困惑。
(图片作者)
显然,你可以利用这些计算来创建更复杂的视觉效果,但是我们可以将上面创建的所有东西结合起来,创建一个如下图所示的仪表板。
(图片作者)
在这篇文章中,我以销售为例,这并不是我最初的图表所要表达的,但这是讨论我所做工作的一种简单方式。这方面的一些其他用例可能希望看到动物行为、员工表现甚至股票价格的变化。
最终,当用户面对迅速变得普遍的大规模数据时,仪表板和报告需要能够只提取最重要的趋势。通过减少甚至消除分析师做这件事所花费的时间,我们可以专注于发现事情背后的原因。
在 Pandas 数据帧中查找和删除重复行
熊猫帮助你开始数据分析的提示和技巧
Susan Q Yin 在 Unsplash 上拍摄的照片
在数据预处理和分析中,您经常需要弄清楚是否有重复的数据以及如何处理它们。
在本文中,您将学习两种方法,duplicated()
和drop_duplicates()
,用于查找和删除重复行,以及如何修改它们的行为以满足您的特定需求。这篇文章的结构如下:
- 查找重复行
- 计算重复行和非重复行
- 用
loc
提取重复行 - 确定用
keep
标记哪些重复 - 删除重复的行
为了演示,我们将使用 Kaggle 上可用的 Titanic 数据集的子集。
import pandas as pddef load_data():
df_all = pd.read_csv('train.csv')
# Take a subset
return df_all.loc[:300, **['Survived', 'Pclass', 'Sex', 'Cabin', 'Embarked']**].dropna()df = load_data()
作者图片
源代码请查看笔记本。
1.查找重复行
要在特定的列上查找重复项,我们可以简单地在该列上调用duplicated()
方法。
>>> df.Cabin.**duplicated()**0 False
1 False
9 False
10 False
14 False
...
271 False
278 False
286 False
299 False
300 False
Name: Cabin, Length: 80, dtype: bool
结果是一个布尔序列,值True
表示重复。换句话说,值True
意味着该条目与前一个条目相同。
要从整体上查看数据帧中的副本,只需在数据帧上调用duplicated()
方法。如果整行与前一行相同,则输出True
。
>>> df**.duplicated()**0 False
1 False
9 False
10 False
14 False
...
271 False
278 False
286 False
299 False
300 False
Length: 80, dtype: bool
为了识别重复的列,我们可以将一个列列表传递给参数subset
:
>>> df.duplicated(**subset=['Survived', 'Pclass', 'Sex']**)0 False
1 False
9 False
10 True
14 True
...
271 True
278 True
286 True
299 True
300 True
Length: 80, dtype: bool
2.计算重复和非重复
duplicated()
的结果是一个布尔序列,我们可以将它们相加来计算重复的次数。在主题后面,True
被转换为1
,而False
被转换为0
,然后将它们相加。
# Count duplicate on a column
>>> df.**Cabin.duplicated().sum()** 11
就像以前一样,我们可以计算数据帧和某些列中的重复数据。
# Count duplicate in a DataFrame
>>> df.**duplicated().sum()** 3# Count duplicate on certain columns
>>> df.**duplicated(subset=['Survived', 'Pclass', 'Sex']).sum()** 70
如果想统计不重复的个数(False
的个数),可以用否定(~
)反过来,然后调用sum()
:
# Count the number of non-duplicates
>>> (**~df.duplicated()**).sum()
77
3.用loc
提取重复行
熊猫duplicated()
返回一个布尔型序列。然而,当我们需要执行一些数据分析时,看到一个True
和False
的列表是不实际的。
我们可以用数据选择器来提取那些重复的行:
# Extract duplicate rows
df.**loc[df.duplicated(), :]**
作者图片
loc
可以接受一个布尔序列,并根据True
和False
过滤数据。第一个参数df.duplicated()
将查找由duplicated()
标识的行。第二个参数:
将显示所有列。
4.确定用keep
标记哪些重复项
在熊猫duplicated()
中有一个争论keep
来决定标记哪些副本。keep
默认为'first'
,这意味着第一个出现的被保留,所有其他的被识别为重复。
我们可以将其更改为'last'
保留最后一次出现的内容,并将所有其他内容标记为重复。
作者图片
我们可以使用第三种选择keep=False
。它将所有重复标记为True
,并允许我们查看所有重复的行。
作者图片
5.删除重复的行
我们可以使用 Pandas 内置方法drop_duplicates()
来删除重复的行。
df.**drop_duplicates()**
作者图片
请注意,我们开始时是 80 行,现在是 77 行。默认情况下,此方法返回删除了重复行的新数据帧。我们可以设置参数inplace=True
来删除原始数据帧中的重复数据。
df.drop_duplicates(**inplace=True**)
确定要保留哪个副本
也可以为drop_duplicates()
设置参数keep
,以确定保留哪些副本。默认为'first'
保留第一次出现的内容,并删除所有其他重复的内容。
类似地,我们可以将keep
设置为'last'
来保留最后一次出现的内容,并删除其他重复的内容。
# Use keep='last' to keep the last occurrence
df.drop_duplicates(**keep='last'**)
我们可以将keep
设置为False
来删除所有重复的内容。
# To drop all duplicates
df.drop_duplicates(**keep=False**)
考虑删除重复的某些列
类似地,为了考虑删除重复的某些列,我们可以将一个列列表传递给参数subset
:
# Considering certain columns for dropping duplicates
df.drop_duplicates(**subset=['Survived', 'Pclass', 'Sex']**)
结论
熊猫duplicated()
和drop_duplicates()
是查找和删除重复的两种快速便捷的方法。了解它们很重要,因为我们经常需要在数据预处理和分析中使用它们。
我希望这篇文章能帮助你节省学习熊猫的时间。我建议你查看一下duplicated()
和drop_duplicates()
API 的文档,并了解你可以做的其他事情。
感谢阅读。请查看笔记本获取源代码,如果您对机器学习的实用方面感兴趣,请继续关注。
你可能会对我的其他一些熊猫文章感兴趣:
- 所有熊猫切()你应该知道把数值数据转换成分类数据
- 使用熊猫方法链接提高代码可读性
- 如何对熊猫数据帧进行自定义排序
- 为了数据分析你应该知道的所有熊猫移位()
- 何时使用 Pandas transform()函数
- 你应该知道的熊猫串联()招数
- Pandas 中 apply()和 transform()的区别
- 所有熊猫合并()你应该知道
- 在 Pandas 数据帧中处理日期时间
- 熊猫阅读 _csv()你应该知道的招数
- 你应该知道的用熊猫 read_csv() 解析日期列的 4 个技巧
更多教程可以在我的 Github 上找到
发现和可视化交互
使用特征重要性、弗里德曼的 H-统计量和 ICE 图分析相互作用
药物的副作用取决于你的性别。与不吸烟者相比,吸烟者吸入石棉会增加患肺癌的几率。如果你更温和/自由,你对气候变化的接受程度往往会随着教育水平的提高而提高。对于最保守的人来说,情况正好相反。这些都是数据交互的例子。识别和合并这些可以极大地提高准确性并改变对模型的解释。
在本文中,我们探索了分析数据集中交互的不同方法。我们讨论如何使用散点图和冰图来可视化它们。然后我们继续寻找/强调潜在互动的方法。这些包括特征重要性和弗里德曼的 H 统计。你可以在 GitHub 上找到用于这个分析的 R 代码。在我们开始之前,有必要解释一下交互的确切含义。
什么是交互?
当一个特征与目标变量有某种关系时,我们说它是可预测的。例如,汽车的价格可能会随着车龄的增长而降低。年龄(特征)可在模型中用于预测汽车价格(目标变量)。在某些情况下,目标变量和特征之间的关系取决于另一个特征的值。这被称为特征之间的相互作用。
以图 1 中年龄和汽车价格之间的关系为例。这里我们有第二个特征——汽车类型。一辆车既可以是老爷车(经典=1),也可以只是普通车(经典=0)。对于普通汽车来说,价格随着车龄的增长而下降,但是对于老爷车来说,车龄实际上增加了它们的价值。价格和车龄的关系取决于车型。换句话说,年龄和车型是有交互作用的。
图 1:汽车价格交互示例
整合这样的交互可以提高我们模型的准确性。非线性模型,如随机森林,可以自动模拟相互作用。我们可以简单地包括年龄和汽车类型作为特征,模型会将交互作用纳入其预测中。对于线性模型,像线性回归,我们必须添加显式交互项。要做到这一点,我们首先需要知道我们的数据中存在哪些交互作用。
资料组
为了解释这些技术,我们随机生成了一个包含 1000 行的数据集。数据集包括表 1 中列出的 5 个要素。这些用于预测员工的年度奖金。我们设计了数据集,因此体验和程度之间以及业绩和销售之间存在互动。days_late 不与任何其他功能交互。
表 1:随机生成的数据集中的字段
由于相关特征的性质,这两种交互是不同的。程度是绝对的,经验是连续的。所以,我们有一个分类和连续特征之间的相互作用。对于另一个相互作用,我们有两个连续的特征。我们会看到,我们仍然以同样的方式分析这些相互作用。
可视化交互
我们可以从使用简单的散点图来可视化这些相互作用开始。在图 2 中,我们看到了经验和程度之间的相互作用。如果员工有学位,他们的奖金会随着经验的增加而增加。相比之下,当员工没有学位时,这些特征之间没有关系。如果这是一个真实的数据集,我们希望对此有一个直观的解释。例如,受过教育的员工可能会承担更看重经验的角色。
图 2:学位-体验互动散点图
同样,我们可以在图 3 中看到销售和绩效之间的相互作用。这种情况下,可能就不那么清楚了。我们现在有一个渐变配色方案,其中较暗的点表示较低的性能评级。一般来说,奖金会随着销售额的增加而增加。仔细观察,你会发现较亮的点有一个较陡的斜率。对于更高的绩效评分,销售额的增加会带来更大的奖金增长。
图 3:销售-绩效互动散点图
以这种方式可视化交互可能很直观,但并不总是奏效。我们只可视化目标变量和两个特征之间的关系。实际上,目标变量可能与许多特征有关系。这一点以及统计变化的存在意味着散点图点将围绕潜在趋势展开。我们已经可以在上面的图表中看到这一点,在真实的数据集中,情况会更糟。最终,为了清楚地看到交互作用,我们需要剔除其他特征和统计变量的影响。
冰原
这就把我们带到了个体条件期望(ICE)图。要创建冰图,我们首先要根据数据拟合模型。在我们的例子中,我们使用了一个有 100 棵树的随机森林。在表 2 中,我们的数据集中有两行用于训练模型。在最后一列中,我们可以看到每个雇员的预测奖金。这是随机森林在给定特征值的情况下做出的预测。为了创建冰图,我们改变一个特征的值,同时保持其他特征不变,并绘制结果预测。
表 2:员工奖金预测示例
查看图 4,这可能更有意义。这里我们在表 2 中取了两个雇员。我们绘制了 days_late 的每个可能值的预测奖金,同时保持其他特性的原始值。(即第一名和第二名员工的工作经验将分别保持在 31 年和 35 年)。两个黑点对应于表 2 中的实际预测值(即它们的真实天数 _ 延迟值)。
图 days _ late 的示例 ICE 图
最后,为了获得 ICE 图,我们对数据集中的每一行都执行这个过程。我们还将每条线居中,使它们在 y 轴上从 0 开始。粗线给出了所谓的部分依赖图 (PDP)。这是每个 days_late 值的平均部分 yhat(居中)值。查看 PDP,随着 days_late 的增加,预计奖金会减少。我们也可以看到,大部分的个体预测都遵循这个趋势。如果 days_late 与另一个特性进行了交互,我们不会想到这一点。我们会有几组不同趋势的预测。
图 days _ late 的居中冰图
您可以通过查看图 6 中的 ICE 图来了解我们的意思。这里有两种截然不同的趋势。那些预测奖金会随着经验增加的员工和那些不会随着经验增加的员工。通过按程度给图着色(即蓝色代表程度,红色代表其他),你可以清楚地看到这是由于经验和程度之间的相互作用。
图 6:学位-经验冰图
我们可以为销售-绩效互动创建一个类似的图表。此处,如果员工的绩效评分高于 5,则该线为蓝色,如果低于 5,则为红色。所有员工的预期奖金都会增加,但绩效评分较低的员工增加速度较慢。对于这两个冰图,相互作用比使用相应的散点图时更清楚。
图 7:销售业绩冰图
这些图非常强大,因为通过保持其他特征值不变,我们可以专注于一个特征的趋势。这就是预测如何因这一特征的变化而变化。此外,随机森林将对数据中的潜在趋势进行建模,并使用这些趋势进行预测。因此,当我们绘制预测图时,我们能够剔除统计变化的影响。
最大限度地利用 ICE 地块
我们使用了随机森林,但冰图实际上是一种模型不可知的技术。这意味着我们可以在创建它们时使用任何模型。但是,模型应该是非线性的(即 XGBoost,神经网络)。线性模型不能以创建这些图所必需的方式来模拟相互作用。模型的选择并不重要,但是根据数据集的不同,不同的模型可能更能捕捉到潜在的交互。
你使用的模型的准确性也不是那么重要。目标是可视化交互,而不是做出准确的预测。然而,你的模型越好,你的分析就越可靠。欠拟合的模型可能无法捕捉交互,而过拟合的模型可能呈现实际上不存在的交互。最后,使用 k-fold 交叉验证或测试集来测试您的模型是很重要的。例如,您可以在图 8 中看到我们随机森林的预测奖金值与实际奖金值的对比图。这个模型并不完美,但我们能够捕捉到潜在的趋势。
图 8:测试集的准确性
仅仅使用冰图可能不足以发现相互作用。根据数据集的大小,可能的交互数量可能会很大。例如,如果你有 20 个特征,你将有 174 个可能的成对交互。想象并试图分析所有这些冰图将是极其乏味的。所以我们需要一种突出/缩小搜索范围的方法。在本文的其余部分,我们将讨论如何使用特征重要性、Friedman 的 H 统计和领域知识来实现这一点。
寻找互动
特征重要性
特征重要性是基于特定特征在多大程度上提高了模型准确性的分数。如果我们在数据集中包含交互术语,我们可以计算这些术语的特征重要性。我们通过添加每个特征的成对乘积(即经验*程度)来实现这一点。然后,我们使用所有交互特征训练模型,并计算结果特征重要性。
在图 9 中,您可以看到 10 个交互特性和 5 个原始特性的特性重要性。这里,我们使用随机森林作为我们的模型,MSE 的百分比增长作为我们的特征重要性分数。我们可以看到,体验度和销售绩效交互术语都具有最高的重要性。这表明这些术语之间存在相互作用。
图 9:交互特性的重要性
您可能还会注意到,其他一些互动术语也很重要(例如,体验、销售)。我们没有预料到这一点,因为在生成数据集时,我们没有包括这两个特征之间的交互。下面的图 10 有助于解释为什么我们会得到这个结果。请注意,经验和销售都与奖金有正相关关系。这意味着这些特征的乘积具有正相关关系。
图 10:体验、销售和体验、销售散点图
这突出了这种方法的缺点。特征对预测的影响可以分为两个部分。第一个是它对预测的直接影响(即主要影响)。第二种是它通过与其他特征的相互作用而产生的效应(即相互作用效应)。由于这两个独立功能的主要影响,experience.sales 交互术语具有很高的功能重要性。因此,我们需要一种方法来将交互效应从主效应中分离出来。
弗里德曼的 H 统计量
弗里德曼的 H-statistics 正是这么做的。为了给出如何计算的概述,我们从拟合模型开始。在我们的例子中,我们使用了与创建 ICE 地块相同的随机森林。然后,我们将观察到的部分相关函数与假设没有相互作用的部分相关函数进行比较。这两种功能的巨大差异表明存在相互作用。
该统计数据有两种版本。第一种通过与所有其他功能的交互来衡量功能的效果。您可以在图 11 中看到这个统计值。值为 1 表示某个特征仅通过交互作用对预测产生影响(即没有主要影响)。值为 0 表示没有交互(即只有主效果)。就经验而言,我们的 H 统计值为 0.28。我们可以把这理解为 28%的体验效果来自于这个特征与其他特征的相互作用。
图 11:总体 h 统计量
H 统计的第二个版本给出了两个特征之间的相互作用的度量。图 12 中的第一个图表给出了体验和其他特征的 H 统计量。我们可以看到,学位和经验之间的相互作用是最重要的。类似地,第二个图表给出了销售的 H 统计。同样,正如预期的那样,我们可以看到与性能的交互是最重要的。
图 12:经验和销售个人 h 统计
其思想是首先使用总体 H 统计量来了解哪些特征具有交互作用。然后,我们可以使用第二个 H-statistic 的图表来识别它们正在交互的其他特征。没有完美的统计数据,这个过程也不总是有效的。你可以看到销售的整体 H 统计值相当低。才 0.11。这接近没有交互的 days_late 的 H 统计量。因此,按照这个流程,我们可能已经决定不进一步分析销售,错过了互动。
领域知识
正如我们在上面看到的,仅仅依靠这些方法,我们可能会错过一些交互或者识别出实际上并不存在的交互。这就是为什么将你所拥有的任何领域知识融入到过程中是很重要的。你可能已经知道了一些可以用这些技术来确认的相互作用。你还应该对发现的任何新的交互进行感知检查。他们应该对自己存在的原因有一个直观的解释。希望通过使用领域知识和这些统计技术的结合,您能够找到一些有用的交互。
成为推荐会员
如果你觉得这篇文章很有帮助并且想看更多,你可以成为我的 推荐会员 来支持我
图像来源
所有图片均为本人或从 www.flaticon.com获得。在后者的情况下,我拥有他们的高级计划中定义的“完全许可”。
参考
[1] A. Goldstein 等人,窥视黑盒内部:用个体条件期望图可视化统计学习(2014),https://arxiv.org/pdf/1309.6392.pdf
[2] C. Molnar,可解释机器学习(2021)https://christophm . github . io/interaction-ml-book/html
[3]互动(统计)(2021),https://en . Wikipedia . org/wiki/Interaction _(统计)
[4] Stat Trek,回归中的相互作用效应(2021),https://stattrek.com/multiple-regression/interaction.aspx
发现并可视化非线性关系
实践教程
用部分相关图(PDP)、互信息和特征重要性分析非线性关系
来源:作者
当你第一次开始开车时,你缺乏经验,有时会更加鲁莽。随着年龄的增长,你获得了更多的经验(和感觉),你卷入事故的可能性变得越来越小(T2)。然而,这种趋势不会永远持续下去。当你上了年纪,你的视力可能会下降,或者你的反应可能会变慢。现在,随着年龄的增长,你卷入事故的可能性越来越大。这意味着事故的概率与年龄成非线性关系。找到并合并这样的关系可以提高模型的准确性和解释能力。
来源:flaticon
在本文中,我们将深入非线性关系。我们将探索如何使用散点图和部分相关图(PDP)来可视化它们。然后,我们将继续探讨突出显示数据中潜在非线性关系的方法。这些包括像特征重要性和交互信息这样的度量。你可以在 GitHub 上找到用于这个分析的 R 代码。在我们开始之前,有必要解释一下非线性关系的确切含义。
什么是非线性关系?
图 1:线性关系的例子
如果两个变量有线性关系,我们可以用一条直线来概括这种关系。该线可以有正斜率或负斜率,但斜率将始终保持不变。您可以在图 1 中看到一个例子。在这种情况下,我们有一个正的线性关系。从另一个角度来看,变量 X 的增加会导致 Y 的增加,不管 X 的初始值是多少。
另一方面,对于非线性关系,由于变量 X 的变化而导致的变量 Y 的变化将取决于 X 的初始值。您可以在图 2 中看到一些例子。上面给出的年龄-事故关系可以是二次的。也就是说,随着年龄的增长,事故发生的概率先降低后升高。归根结底,任何不能用直线概括的关系都是非线性关系。准确地说,这些也包括互动,但是我们在另一篇文章中关注这些类型的关系。
图 2:非线性关系的例子
非线性模型,如随机森林和神经网络,可以自动模拟上述非线性关系。如果我们想使用线性模型,比如线性回归,我们首先要做一些特征工程。例如,我们可以向数据集添加年龄来捕捉二次关系。为了进行更有效的特征工程,首先在我们的数据中找到这些关系是有帮助的。
资料组
为了帮助解释我们如何找到这些关系,我们将使用一个随机生成的数据集。您可以在表 1 中看到特性列表,其中价格 是我们的目标变量。我们将尝试使用这 4 个特征来预测二手车的价格。数据集已经被设计成使得车龄和修理与价格具有非线性关系。而 km_driven 具有线性关系,而 owner_age 没有关系。
表 1:随机生成的数据集中的字段
你可以在图 3 的散点图中看到我们的意思。这里我们可以看到这两个特征之间的非线性关系。如果这是一个真实的数据集,我们可以期待一些直观的原因。例如,汽车的价格随着年龄的增长而下降是有道理的,但是为什么它会开始上涨呢?也许大部分老爷车都是经典的\有收藏价值的车,所以价格会随着车龄的增长而上涨。
图 3:非线性关系散点图
我们可以为修复功能提出类似的叙述。这是汽车接受服务或维修的次数。在它的一生中,它是正常的日常服务。因此,该特性的小值可能表示汽车被忽略了。另一方面,较大的值可能表明汽车需要这些标准服务之外的额外维修。这些车将来可能会给新车主带来更多问题。
您可以在图 4 中看到剩余的关系。如前所述车主 _ 年龄,与价格无关。我们可以在图表中看到这一点,因为这些点是随机分布的。我们还可以看到 km_driven 与价格成负线性关系。我们包括了这些,因为它将有助于比较这些关系与非线性关系的分析。
图 4:线性关系散点图
像这样的散点图是可视化非线性关系的简单方法,但它们并不总是有效。对于每张图表,我们只可视化目标变量和一个特征之间的关系。实际上,目标变量将与许多特征有关系。这一点以及统计变量的出现意味着这些点将围绕潜在趋势展开。我们已经可以在上面的图表中看到这一点,在真实的数据集中,情况会更糟。最终,为了清楚地看到关系,我们需要剔除其他特征和统计变量的影响。
部分相关图
这就把我们带到了 PDP。要创建 PDP,我们首先必须使模型符合我们的数据。具体来说,我们使用一个有 100 棵树的随机森林。在表 2 中,我们的数据集中有两行用于训练模型。在最后一栏,我们可以看到二手车的预测价格。这些是随机森林在给定特征值的情况下做出的预测。
表 2:汽车价格预测示例
为了创建 PDP,我们首先改变一个特性的值,同时保持其他特性不变。然后,我们绘制每个特征值的预测结果。查看图 5,这可能更有意义。在这里,我们已经取得了表 2 中的两辆汽车。我们已经为汽车年龄的每个可能值绘制了预测的价格(部分 yhat ),同时保持其他特性的原始值。(例如维修将保持在 25 和 12)。这两个黑点对应于表 2 中的实际预测值(即实际的汽车年龄)。
图 5:示例的预测图
我们对数据集中的每一行都遵循这个过程。你可以在图 6 中看到所有这些单独的预测线。最后,为了创建 PDP,我们计算汽车年龄的每个值的平均预测值。这由加粗的黄线显示。您现在可以清楚地看到非线性关系。也就是说,预测价格最初会下降,但随后会上升。类似地,我们可以在图 7 中看到维修的非线性关系。
图 6:汽车时代的 PDP
图 7:维修的 PDP
相比之下,我们可以在图 8 中看到 km_driven 的 PDP,在图 9 中看到 owner_age 的 PDP。如前所述, km_driven 与价格成线性关系。我们可以在平均预测值线性下降的 PDP 中看到这一点。同样,和 owner_age 也没有关系。这里的平均预测值保持相当恒定。
图 8:km _ driven 的 PDP
图 9:所有者年龄的 PDP
这些图提供了趋势的更清晰的图像,原因有二。首先,通过保持其他特征值不变,我们可以专注于一个特征的趋势。这就是预测如何因这一特征的变化而变化。其次,随机森林将对数据中的潜在趋势进行建模,并使用这些趋势进行预测。因此,当我们绘制预测图时,我们能够剔除统计变化的影响。
充分利用您的 PDP
查看图 10,您可以了解用于创建这些 PDP 的随机森林的准确性。这个模型并不完美,但在预测汽车价格方面做得相当不错。事实上,模型的准确性并不那么重要。目标是可视化非线性关系,而不是做出准确的预测。然而,你的模型越好,你的分析就越可靠。拟合不足的模型可能无法捕捉到关系,而拟合过度的模型可能会显示实际上并不存在的关系。
图 10:测试集的准确性
型号的选择也不是那么重要。这是因为 PDP 是一种与模型无关的技术。在此分析中,我们使用了随机森林,但您也可以使用任何非线性的森林,如 XGBoost 或神经网络。根据数据集的不同,不同的模型可能更善于捕捉潜在的非线性关系。
寻找非线性关系
仅仅使用 PDP 可能不足以发现非线性关系。这是因为您的数据中可能有许多特征,尝试分析所有的 PDP 将非常耗时。我们需要缩小搜索范围的方法。也就是说,我们需要一个指标来告诉我们,我们的特征和目标变量之间是否有显著的关系。然后,我们可以专注于这些功能。在本文的其余部分,我们将探索如何使用特性重要性或交互信息来实现这一点。
为什么我们不能使用相关性
在我们深入研究这些指标之前,有必要讨论一下为什么相关性不合适。皮尔逊相关系数是一个用于发现重要关系的常用指标。然而,它是线性相关性的度量,意味着它只能用于查找线性关系。我们可以在图 11 中看到这一点,其中在 km_driven 和价格之间有很大的负相关性。相比之下,车龄的相关性要低很多。
图 11:功能和汽车价格的相关性
在某些情况下,线性趋势可能擅长逼近非线性趋势。因此,即使对于非线性关系,我们仍可能看到一些高相关值。我们可以从修复特征中看到这一点,其中仍然存在相当大的负相关性。总的来说,这个指标不能帮助我们识别非线性关系。
交互信息
互信息给出了一种测量方法,通过观察一个变量,一个变量周围的不确定性减少了多少。这是通过比较变量的联合分布和边际分布的乘积来实现的。如下所示,独立变量的联合分布将等于它们的边际分布的乘积。因此,如果联合分布不同,则表明存在相关性,我们将计算更高的互信息值。最终,相关性意味着两个变量有关系。
对于独立变量:f(x,y) = f(x)f(y)
两个变量的依赖关系不一定是线性的。这意味着该指标可用于突出非线性关系。参见图 13 中的价格和我们的 4 个特征之间的交互信息值。与相关性相比,我们现在可以看到,与目标变量有关系的所有特性都有更高的值。
图 13:特性和汽车价格的交互信息
在这个分析中,我们只看了连续变量。互信息也可以用于离散变量。即一个变量是离散的,另一个是连续的,或者两个变量都是离散的。这是相对于相关性的另一个优势,因为相关性只能用于连续变量。
特征重要性
另一种方法是首先训练一个模型,然后使用该模型的特征重要性分数。特征重要性给出了特定特征在多大程度上提高了模型精度的度量。在图 12 中,您可以看到从我们用来创建 PDP 的同一个随机森林中获得的分数。具体来说,我们使用 MSE 增加的百分比作为特性重要性的度量。
图 12:特性重要性(MSE 增加的百分比)
与 PDP 一样,我们可以使用任何模型来实现这种方法,只要它是非线性的。我们不能使用线性模型,如线性回归,因为它们不能模拟非线性关系。换句话说,具有非线性关系的特征可能不会提高准确性,从而导致较低的特征重要性分数。
最后,我们可以使用互信息和特征重要性来突出非线性(和线性)关系。然而,这些指标并没有告诉我们这些关系的本质。也就是说,关系是二次的、指数的、逐步的,等等。因此,一旦我们强调了这些潜在的关系,我们必须回到 PDP 来确定它们的性质。
如前所述,互动是一种特殊类型的非线性关系。当目标变量和特征之间的关系依赖于另一个特征的值时,就会出现这种情况。我们在下面的文章中以类似的方式分析这些类型的关系。
成为推荐会员
如果你觉得这篇文章很有帮助并且想看更多,你可以成为我的 推荐会员 来支持我
图像来源
所有图片均为本人或从 www.flaticon.com获得。在后者的情况下,我拥有他们的高级计划中定义的“完全许可”。
参考
[1] C. Molnar,可解释机器学习(2021)https://christophm . github . io/interaction-ml-book/html
通过人工智能驱动的内容营销寻找客户
[图像归属](https://pixabay.com/users/kevinking-289243/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=424521">Kevin King(Chandana Perera) from <a href="https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=424521)
有些事情看似显而易见,但当你问一个具体的问题时,却得不到明确的答案。其中一个问题是如何利用互联网做生意。我在咨询有关使用人工智能改善业务功能时提出了这个问题,大多数答案充其量是“模糊的”。
在深入本文的主题之前,让我们定义一个非详尽的使用互联网进行商业活动的方式列表,而不考虑行业或商业活动类型(例如,从创业到医疗保健实践)。)
利用互联网做生意的方法
电子商务
【客户访问网站,订购产品,通过支付网关付款,商品送货上门。
公司网站
·提供知名度、宣传、品牌、新闻、财务结果、支持等
软件即服务(订阅)
CRM
供应商和员工管理
组织、信息和沟通
市场调查
【新产品潜力、竞争对手、标准、产品评论
云托管
【外包 IT 需求】
广告
销售广告:新闻&社交媒体(如 NYT、脸书、推特、LinkedIn)
通过广告销售:内容营销(如博客、medium.com、影响者)
进一步分析这个概念,我们看到它不是一维的。如果考虑实施模式,则该概念最好在 3d 空间中建模。因此,这三个维度是网络、移动和即将到来的增强虚拟现实 IOT,反映了不同的交付和交互模式(见下图)
三维空间
在上述范围内,我们将重点关注内容营销。
什么是内容营销
内容营销是一种营销方式,专注于持续创造和分享有价值的、高度相关的内容,以吸引和保留明确定义的受众,从而推动有利可图的客户行动。
没有人喜欢被直接卖给。无论是在数字上被追逐为“线索”或“潜在客户”,还是走进一家商店并被“我能帮什么忙”(翻译为“你不能只是浏览,你必须买些东西”)所困扰,它都没有很好的效果。
任何企业、服务或实践都需要能够快速回答的问题是“你如何找到客户?”。作为一个企业主,如果答案是“毫无头绪,事情就这么发生了”,那么至少还有显著改善的空间。通常的答案是“广告”,然后的问题是如何,在哪里和多少。
高效、有影响力的广告需要给广告“消费者”带来价值。如果一个广告要在寻找顾客或至少诱导顾客购买方面起作用,它需要对所花费的注意力有所回报。一个恼人的广告充其量只是不起作用,但在许多情况下会对品牌有害(以及成本影响)。
随着部分“生锈”的销售机制释放出被压抑的需求,在新冠肺炎危机爆发的一年内通过接种疫苗进行控制的可能性将导致增长反弹。因此,需求和购买的需要是存在的,企业需要为这个机会做好准备,部分是通过重新评估他们的销售业务。
广告类型和提供的价值
专注于任何营销传播中所需的附加值,一些广告的幽默内容提供了这种价值(见下文)。
其他人提供教育,而其他人则伪装成提供一些娱乐的文章,例如“申请世界上最好的工作”,实际上只是宣传一个加勒比海岛屿,或者“她错误地使用“xyz”消息平台向她的老板发送了一条 x 级消息”。
但是最强大的,有机的客户获取方法是内容营销。
与许多人可能相信的相反,网络和当前的技术并没有产生这个概念。内容营销至少从上个世纪就已经存在了。最近发生的变化是可访问性大大增强。
这同样适用于“免费增值”商业模式(“免费”和“溢价”是一种定价策略,通过这种策略,免费提供基本产品或服务,但金钱(溢价)是用于附加功能或服务)。
在讨论内容营销的未来之前,下面描述了一些有意义的历史例子来说明上述观点。
内容营销—约翰迪尔
1895 年,约翰迪尔开始出版一本名为《犁沟》的杂志,旨在教育农民如何有效地管理他们的作物。它是免费的,没有推广 John Deere 产品。当时没有电视、广播或互联网,但印刷机技术刚刚起步,并在世界各地被用于创作和接触观众。
不涉及销售,但通过向普通农民和牧场主提供这些内容,John Deere 成为了思想领袖,并使用内容营销将农业与品牌联系起来。《犁沟》现在在 40 多个国家以 12 种语言出版,完全在线,相关内容通过社交媒体渠道发布。这种内容营销方法使 John Deere 成为农业的同义词。
内容营销——米其林
“米其林指南”创作于 1900 年左右,是一本免费的车主指南(当时车主很少),教育他们如何使用和保养车辆。作为轮胎生产商,米其林并不关注轮胎,而是希望建立一个受众群体,为他们提供免费的旅行建议。这包括如何处理磨损、地图、如何换轮胎的信息、哪里可以找到汽油等等。汽车使用得越多,对新轮胎的需求就越大。
免费增值模式——杰克·丹尼尔的
1884 年,19 岁的杰克·丹尼尔买下了一家酒厂,开始了自己的威士忌生产。作为一名营销天才,他在几个月内建立了这个品牌,在整个田纳西州的销售中排名第二。他是第一批在瓶子上印上商标的人之一,并很快意识到把瓶子做成黑色和方形能使他的产品与众不同。
至少在 20 世纪 50 年代之前,杰克·丹尼尔(Jack Daniel)有意识地保持供应小于需求,将“稀缺”作为一种销售策略。他使用一种混合的“免费增值”模式来推广自己的品牌,创建了一个乐队,名为“杰克丹尼尔原创银短号乐队”,在当地一家酒吧免费演奏音乐,并与老板达成协议,将他的威士忌卖给他的客户。
人工智能驱动的内容营销人工智能驱动的内容可以改变任何企业的游戏规则。无论您想要理解您的数据,实现内容创作还是个性化内容,AI 都有能力提供帮助。
AI 在内容营销中是如何运用的
我们来探讨一下 AI 目前在内容营销中运用的最流行的方式。
1。基于对客户需求理解的个性化内容(包括电子邮件)更有可能作为间接的购买建议产生影响。
个性化内容必须写得很好,具有良好的视觉效果,必须提供真正的附加值。
满足并超越观众的期望能创造持久的纽带,让顾客的需求得到关注。
人工智能的最新进展使得内容个性化变得有效可行。机器学习有助于跟踪消费者的行为、偏好以及他们与内容的互动。这可以走得更远,一些人工智能系统使用多种数据源提供实时全面的访客资料。
2。预测分析
预测分析使用机器学习模型来预测未来事件。与内容营销相关的此类模型的示例有:
聚类模型
聚类是一种涉及数据点分组的机器学习技术。这些算法可以用于基于过去的品牌参与、过去的购买和人口统计数据的受众细分。
推荐模型
推荐系统是一类向用户提供个性化建议的机器学习算法。这些模型分为协作过滤和基于内容两类,帮助用户发现新产品和新服务,引导他们找到最有可能购买的产品。
倾向模型
这些模型试图预测访问者和客户采取某些行动的可能性,如对报价采取行动或退出。
3。客户细分客户细分是一种将客户划分为具有不同需求的不同群体的方式。K-means 聚类是一种流行的无监督机器学习算法,它可以找到不同的“聚类”(组),使它们尽可能小。目标是创建尽可能多的不同组。
然后,可以根据客户群的概况(例如,如何联系他们,通过邮件或短信等)对客户群进行不同的称呼。
上面描述的三种方法是最常用的,但是在营销中使用人工智能还有很多方法,包括:
媒体购买优化
对话式人工智能(聊天机器人)
增强和虚拟现实
面部识别
生物识别
通过网络、电子邮件和社交媒体,内容营销是获得客户的一种强有力的方法。但是,内容的创建和管理是一项重要的任务。
为了帮助这一点,各种人工智能技术可以并且正在被使用,如上所述。
内容营销的概念可以通过实际创建一个利基社交媒体平台来进一步发展,通过这个平台来创造观众和分享个性化的内容。
关于作者
使用 Python 查找重复图像
在您的计算机上自动搜索重复图像
图片由 KissCC0 提供。
你有没有发现自己在经历过数百张,甚至数千张的图像后,才发现有些其实看起来有点太像?它们会是复制品吗?然后你可能检查了两个图像分辨率,然后删除了最低的一个。
我多次发现自己处于这种情况。很痛苦,很费时间,很累。特别是,如上所述,如果你必须通过成千上万的图像。此外,有些图像乍一看可能很容易被归类为重复的,但有些图像可能需要精确检查,也可能导致您删除图像,而实际上并没有重复。
那时我想:让我们自动化这个过程。
在今天的文章中,我将介绍为自动搜索本地计算机上文件夹中的重复图像编写一个 Python 3.8 脚本的过程。
1 |理论上:将图像转换为数字数据
为了将图像相互比较,我们需要以某种方式将它们转换成可比较的、计算机可读的数据。你们中熟悉机器学习和计算机视觉的人可能已经知道,图像可以被转化为矩阵,或者更准确地说,转化为张量。一个张量是一个可以保存 n 维数据的容器。因此,矩阵是一个二维张量。
图片由 Mukesh Mithrakumar 从开发到
彩色图像中的每一个像素都可以用红色、绿色和蓝色的组合来表示。这三种颜色组成了这个像素的独特颜色。
如果我们有一个红色矩阵,一个绿色矩阵和一个蓝色矩阵来代表图像中的所有像素,我们可以将这三个矩阵相互叠加,最终得到一个张量。🎉
来自 Slideshare.net 的伯尔顿·恩肖的图片
这太棒了,因为这意味着我们可以用数字来表示我们的图像。现在应该已经敲响了警钟:数字很容易相互比较。假设一幅图像和另一幅图像由完全相同的张量组成,我们可以得出结论:这些是复制品!
很好,现在让我们继续,看看我们如何将理论应用于实践。
2 |实践:将图像转换为数字数据
让我们首先导入我们将用于这个脚本的 Python 库: skimage 、 matplotlib 、 numpy 、 openCV 、 os 和 imghdr 。
我们将从编写函数 create_imgs_matrix 开始。这是我们的最后一个函数,但是您可以随意查看下面代码的详细解释:
该函数将为我们的算法在特定文件夹中找到的每幅图像创建一个张量。我们读入我们的计算机目录,遍历所有的文件,并确保我们的文件夹中的文件格式实际上是图像(即 JPG,PNG 等。).有一个非常方便的库叫做 imghdr 可以在这个过程中帮助我们。
我们首先检查文件是否可以通过以下方式访问:
os.path.isdir(directory + filename)
然后我们检查它是否是一个图像:
imghdr.what(directory + filename)
如果它不是一个图像,这个函数将返回 None ,并因此移动到目录中的下一个文件。如果两个输出都有效,该函数将继续下一行,在这里我们使用 opencv 库来解码我们的图像文件并将其转换为张量:
img = cv2.imdecode(np.fromfile(directory + filename, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
然后,我们检查它是否已经成功地转换为一个 n 维数组,并确保我们的张量最多有 3 层。
在我们的最后一步,我们调整我们的图像张量的像素大小为 50,也就是说,我们希望它的像素宽度和高度为 50。我们这样做是为了加快图像的比较过程。如果我们有高分辨率图像,它们各自的张量也将非常大,因此导致与其他图像张量相比,一对一比较的计算时间更长。
最后,我们将调整后的张量添加到我们的 imgs_matrix 列表中,并继续处理我们目录中的下一个文件(如果存在的话)。
酷——在我们写完这个函数之后,我们得到了目录中所有图像的张量列表。现在,我们如何比较这些呢?为此,我们将使用一个名为 MSE 的指标。
图像相似性的 3 | MSE(均方误差)
统计领域经常使用 MSE 或均方误差 T5。对于我们的用例,我们将使用它来比较两幅图像的相似程度。
两幅图像之间的均方误差是两幅图像之间的平方差之和。误差越小,图像越“相似”。
MSE 计算如下:
图片来自维基百科
我不会详细介绍这个公式的作用,而是让我给你一个 Python 代码中的等价形式:
这个函数计算 imageA 和 imageB 之间的 MSE,并将返回一个浮点值,我们可以将它解释为这些图像之间的相似性。这个数字越低,这些图像越相似。
4 |查找重复项的最后提示和注意事项
在进入最后一章之前,让我给你一些我在这个项目中学到的技巧和思考。
A.选择什么目标 MSE?
因为我们寻找的是重复的图像,而不仅仅是相似的图像,我们可以假设 MSE 为 0 是我们确信图像是重复的目标吗?
总的来说,是的。但是在我们的例子中:还记得我们将图像的尺寸调整为 50 像素宽 x 50 像素高吗?这可能会导致给出具有不同初始分辨率或大小的图像的略微不同的张量。当我自己编写这个函数时,我看到一些确实是重复的图像,不知何故没有导致 MSE 为 0。因此,更好的做法是将我们的 MSE 阈值设置得高一点,这样我们就可以确保捕捉到所有重复的图像,即使没有完全相同的张量。
对于这个用例,我选择 200 的 MSE 作为最大阈值。一旦两个图像的 MSE 低于 200,我们就认为它们是重复的。
B.那些旋转的图像是怎么回事?
这也是我写完第一个初始函数后才意识到的。当然,根据我们的图像旋转,我们的图像的张量会看起来不同。因此,我们需要确保将我们的图像与第二幅图像的所有可能的旋转进行比较。
图片来自 KissCC0 由作者修改
借助内置的 rot90 函数,numpy 库可以让我们轻松地执行这个操作,这个函数可以将矩阵旋转 90 度。
C.比较图像分辨率
当然,除了寻找重复,我们还希望我们的算法帮助我们决定哪些可以删除。因此,我们希望比较图像的原始分辨率,并让我们的算法输出最低的文件名。
我们将通过使用 os.stat st_size 函数来完成这项工作,该函数将输出文件大小。具有较小大小的文件将被添加到单独的列表中。
5 |将所有这些放在一起
首先,祝贺你一直坚持到现在,并走了这么远。我们到了最后一章,我们将把所有的东西放在一起!
总结我们的步骤:
- 计算文件夹中所有图像的图像张量。
- 逐一检查所有图像张量并计算它们的 MSE。在此过程中,我们确保将图像旋转 90 度,这样即使这些图像没有相同的初始方向,我们也可以找到重复的图像。
- 如果我们的两个图像的 MSE< 200, classify them as duplicates.
- Check the file size of the original two files. The one having the lower size will be added to a list of images that can be deleted.
Instead of pasting the full code here, I will share with you the link to my GitHub 库,我已经上传了完全复制图像查找器(DIF)脚本。
https://github.com/elisemercury/Duplicate-Image-Finder
*** | 2021 年 10 月更新**
DIF 现在也可以作为 Python 包 difPy 供您通过 pip 安装程序进行安装。
https://pypi.org/project/difPy/
您现在可以只使用pip install difPy
并如下使用该库:
我希望这篇文章对您有所帮助,并且可以帮助您节省一些宝贵的图像比较和重复数据删除时间!至少对我个人来说是这样的。😜
如果您有任何问题或反馈,请随时联系我,或者在下面发表评论,让我知道您的想法。
参考资料:
[1] A. Rosebrock,如何:Python 比较两幅图像 (2014)
[2] J. Brownlee,用 NumPy 对用于机器学习的张量的温和介绍(2018)
在影像分类数据集中查找硬样本
挖掘硬样本是改进机器学习数据集的有效方法,本指南将向您展示如何自己去做
蒂姆·福斯特在 Unsplash 上的照片
假设你有一个数据仓库,里面有数百万张未标记的图片。您成功地标记了数据的子集,并在其上训练了图像分类模型,但它的表现不如您希望的那样好。你如何决定给哪些新样本添加注释并添加到你的训练集中?
您可以随机选择新的样本进行注释,但是有一个更好的方法。硬样本挖掘是一种屡试不爽的方法,可以将大量未标记的原始数据提取为更小的高质量标记数据集。
硬样本是指你的机器学习(ML)模型发现很难正确预测标签的样本。
在影像分类数据集中,硬样本可以是任何东西,从看起来像狗的猫到分辨率模糊的影像。如果您希望您的模型在这些硬样本上表现良好,那么您可能需要“挖掘”这些硬样本的更多示例,以添加到您的训练数据集中。在训练期间将您的模型暴露于更硬的样本将允许它在以后对这些类型的样本执行得更好。
硬样本不仅对训练数据有用,还必须包含在测试集中。如果您的测试数据主要由简单的样本组成,那么您的性能将很快达到上限,导致进度停滞。将硬样本添加到测试集将使您更好地了解模型在硬边缘情况下的表现,并可以更深入地了解哪些模型更可靠。
这个演练在 Colab 中运行 (ipynb 链接在此)(图片由作者提供)
概观
这篇文章将带你了解如何使用我正在开发的新的开源 ML 工具 FiftyOne ,在你的数据集中寻找硬样本。为了使本演练易于理解,我们将使用现有的模型和数据集。即 ResNet50 在 CIFAR-10 数据集测试分裂中寻找硬样本。
它将指导您如何:
设置
本演练将使用 GitHub 上的 PyTorch 和fiftone以及 PyTorch_CIFAR10 的模型。PyTorch 和 FiftyOne 的安装说明很简单:
pip install torch torchvision
pip install fiftyone
加载您的数据
对于本例,我们将使用影像分类数据集的测试分割, CIFAR-10 。该数据集包含 10,000 个测试图像,标记了 10 个不同的类别。这是51 数据集动物园中的几十个数据集之一,所以我们可以很容易地加载它。
我们可以使用 FiftyOne App 来看看这个数据集。
CIFAR-10 和地面真相标签在51 应用中可视化(图片由作者提供)
注 :也可以将自己的数据集加载到五十一中。它支持许多计算机视觉任务的标签,包括分类、检测、分割、关键点和更多。例如,如果数据集包含存储在每个类的目录中的图像,可以使用下面的代码来加载它。
添加逻辑
为了计算第五十一张图像的硬度,你首先需要使用一个模型来计算这些图像的对数。您可以使用任何您想要的模型,但理想情况下,它将是一个经过训练的类似数据,并且在相同的任务中,您将使用这些新图像。
在本例中,我们将使用来自 PyTorch CIFAR-10 库的代码,即预训练的 ResNet50 分类器。
# Download the software
git clone --depth 1 --branch v2.1 https://github.com/huyvnphan/PyTorch_CIFAR10.git
# Download the pretrained model (90MB)
eta gdrive download --public \
1dGfpeFK_QG0kV-U6QDHMX2EOGXPqaNzu \
PyTorch_CIFAR10/cifar10_models/state_dicts/resnet50.pt
您可以轻松地将带有逻辑的分类字段添加到 51 个数据集中的样本中。
计算硬度
第五十一个大脑包含了各种有用的方法,可以让你深入了解数据。此刻,你可以计算出你的数据的唯一性,最难的样本,以及注释的错误。这些都是在数据集上生成标量指标的不同方法,可让您更好地了解现有数据的质量,并选择高质量的新数据样本。
加载数据集并将 logits 添加到样品后,您可以在一行代码中计算硬度。硬度算法是闭源的,但基本思想是利用模型预测的相对不确定性,为每个样本分配一个标量硬度值。
探索和识别最难的样本
您可以使用 FiftyOne 应用程序可视化您的数据集,并探索硬度最高和最低的样品。
数据集排序以显示最难的样本(按作者排序的图像)
虽然这个例子使用的是 CIFAR-10 的小图像,但 FiftyOne 也可以处理高分辨率图像和视频。
我们可以编写一些查询来更深入地挖掘这些硬度计算,以及它们如何与数据的其他方面相关联。例如,我们可以分别在模型的正确和错误预测上看到硬度的分布。
正确和错误预测样品的硬度分布(图片由作者提供)
如您所料,上图显示正确预测的硬度分布偏向较低的硬度值,而不正确的预测在高硬度值时分布更均匀。这表明模型预测不正确的样本往往是更难的样本。因此,向训练集添加更难的样本应该会提高模型性能。
我们还可以看到样品的硬度如何分布在不同的类别中。
Average classwise hardness
cat: 0.703082
dog: 0.628436
airplane: 0.591202
bird: 0.588827
frog: 0.577954
truck: 0.573330
horse: 0.564832
deer: 0.561707
automobile: 0.554695
ship: 0.553041
看起来猫和狗是最难的职业,所以在其他职业之前添加更多的例子是值得的。
分类准确度与硬度(图片由作者提供)
我们可以看到,一个类中样本的平均硬度与该类上模型的精度存在反相关关系。
我们来看看最难类“猫”的错误预测样本。
最难的错误预测样本最难的类别“猫”(图片由作者提供)
现在让我们来看看硬度最低的猫的正确预测图像。
最难正确预测最难类别“猫”的样本(图片由作者提供)
将最难预测错误的猫图像与最容易预测正确的猫图像进行比较,我们可以看到,该模型在对直视相机的猫面部图像进行分类时要容易得多。模特最难处理的猫的图像是那些光线不好、背景复杂的猫的图像,以及它们没有坐着面对摄像机的姿势。现在,我们对添加到这个数据集中的猫图像的类型有了一个概念。
下一步是什么?
这个例子是在一个先前注释过的数据集上完成的,目的是展示硬度与数据集的其他方面的关系。在现实世界的应用程序中,您现在可以将此方法应用于新的未标记数据。
一旦确定了可用的最难样本,就该更新数据集了。您可以选择硬度值最高的 X 个样本发送出去,进行注释并添加到您的训练或测试集中。或者,您可以根据上面计算的每个等级的硬度按比例选择样本。
根据这些新数据重新训练你的模型现在应该可以让它在更困难的情况下表现得更好(我正在写一篇后续博文来展示这一点)。此外,如果模型在测试集上表现良好,将这些样本添加到测试集将使您对模型在新的未知数据上表现良好的能力更有信心。
使用 NMF 在数据中寻找模式
使用 Ecco 对文本数据进行非负矩阵分解
使用 EECO 的 NMF 可视化(来源:作者)
自然语言处理是人工智能领域最热门的话题之一。它有助于构建聊天机器人、语音助手、情感分析、推荐引擎等应用。这是一个新兴领域,大多数相关公司都在投资和研究创造下一代语音助手。
自然语言处理最重要的算法之一是主题建模,它有助于描述文本数据集中的数量趋势,并找出数据集的概要特征。换句话说,这是一种特征工程,我们在数据集中找出最重要的特征。
NMF 是一种无监督的主题建模技术,其中没有提供训练数据或数据标签。它将高维数据分解为低维表示。
Ecco 是一个开源的 Python 库,它提供了使用交互式可视化来探索和解释 NLP 模型的多种功能。
在本文中,我们将使用 Ecco 来执行 NMF,并为其创建一个交互式可视化。
让我们开始吧…
安装所需的库
我们将从使用 pip 安装 Ecco 开始。下面给出的命令可以做到这一点。
pip install ecco
导入所需的库
在这一步中,我们将导入所需的库和函数来创建 NMF 可视化。我们还将从 eeco 加载预训练的 Bert 模型。
import ecco
lm = ecco.from_pretrained('bert-base-uncased', activations=True)
加载预训练模型(来源:作者)
对文本进行标记
在这一步中,我们将对用于 NMF 可视化的数据进行符号化。你可以用任何你想要的文字,我正在写一篇关于萨钦·坦杜尔卡尔的文章。
text = ''' Sachin Tendulkar has been the most complete batsman of his time, the most prolific runmaker of all time, and arguably the biggest cricket icon the game has ever known. His batting was based on the purest principles: perfect balance, economy of movement, precision in stroke-making, and that intangible quality given only to geniuses - anticipation. If he didn't have a signature stroke - the upright, back-foot punch comes close - it's because he was equally proficient at each of the full range of orthodox shots (and plenty of improvised ones as well) and can pull them out at will.There were no apparent weaknesses in Tendulkar's game. He could score all around the wicket, off both front foot and back, could tune his technique to suit every condition, temper his game to suit every situation, and made runs in all parts of the world in all conditions.Some of his finest performances came against Australia, the overwhelmingly dominant team of his era. His century as a 19-year-old on a lightning-fast pitch at the WACA is considered one of the best innings ever to have been played in Australia. A few years later he received the ultimate compliment from the ultimate batsman: Don Bradman confided to his wife that Tendulkar reminded him of himself.Blessed with the keenest of cricket minds, and armed with a loathing for losing, Tendulkar set about doing what it took to become one of the best batsmen in the world. His greatness was established early: he was only 16 when he made his Test debut. He was hit on the mouth by Waqar Younis but continued to bat, in a blood-soaked shirt. His first Test hundred, a match-saving one at Old Trafford, came when he was 17, and he had 16 Test hundreds before he turned 25\. In 2000 he became the first batsman to have scored 50 international hundreds, in 2008 he passed Brian Lara as the leading Test run-scorer, and in the years after, he went past 13,000 Test runs 30,000 international runs, and 50 Test hundreds. '''
inputs = lm.tokenizer([text], return_tensors="pt")
output = lm(inputs)
使用 NMF 和 EECO 分解文本
这是最后一步,我们将创建 NMF 的可视化,我们将使用两种类型的因式分解,即所有层的因式分解和第一层的因式分解。
#All layers
nmf_1 = output.run_nmf(n_components=10)
nmf_1.explore()
NMF 所有层(来源:作者)
#First Layer
nmf_2 = output.run_nmf(n_components=8, from_layer=0, to_layer=1)
nmf_2.explore()
第一层 NMF(来源:作者)
在这里,我们可以清楚地看到只用一行代码创建的 NMF 可视化效果。这些可视化是互动的,高度可解释的。我们可以清楚地分析 NMF 在可视化中的不同主题和权重。
继续尝试不同的数据集,并创建美丽的可视化。如果您发现任何困难,请在回复部分告诉我。
本文是与 Piyush Ingale 合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github*简介针对不同的数据科学项目和包教程。还有,随意探索* 我的简介 ,阅读我写过的与数据科学相关的不同文章。
为您的数据科学项目查找卫星图像
Sentinel Hub,为您的数据科学项目提供卫星图像的最佳资源之一
如今,你可以用卫星图像做很多事情,无论是在你的地理分析系统中使用,还是在 R/Python 或任何其他编程语言上帮助你进行统计分析。
你将(也应该)问自己的第一个问题是:我在哪里可以找到这些卫星图像?这个问题的答案就在这里。我将向您展示您可以从世界任何地方找到高质量卫星图像的最佳资源。
接下来,我将展示如何从特定区域获取这些图像。我会选择波尔图——葡萄牙🇵🇹的一座美丽的海滨城市,作为我的工作区域,因为那是我居住的地方。IMO 获取卫星图像的最佳来源是:
**https://apps.sentinel-hub.com/eo-browser/
- 注册一个账户,简单快捷。使用最近创建的帐户登录,您将看到以下屏幕:
2.缩小地图,将地图移动到您希望获取卫星图像的位置。点击“搜索”,你会看到覆盖你所选区域的所有图片。
3.选择最适合你的图像,例如,云层最少的图像通常最适合进行任何类型的分析。当你找到你喜欢的,点击此按钮进入下载链接:
点击第二个链接开始下载。它将打开一个新的页面,并要求用户和密码。这和你几分钟前登录网站用的信息是一样的。输入用户和密码,下载将立即开始。
仅此而已。几分钟后,您将获得所需的卫星图像,并可以在您选择的软件中打开它们,无论是 SNAP、ArcGIS、RStudio 还是任何其他您想要的软件。
Sentinel Hub 的其他一些功能和注意事项
- 你也可以选择从另一颗卫星上获取图像。Landsat 是另一个非常受欢迎的获取图像的选择(这里也有)
- 日期过滤器将允许您选择一个月或一段时间:
您可以直接在 Sentinel Hub 的界面上使用地图,进行如下操作:
- 放置标记,测量距离:
- 计算面积:
还可以用你选择的地图制作延时视频或动画。
最后的想法
这就是你需要了解的关于哨兵枢纽的基本知识。我相信这是为您的数据科学项目下载卫星图像的最佳资源之一。
查看一些由阿卜迪沙库尔、阿德里安·塞拉皮奥和阿努巴夫·帕特奈克撰写的关于地理空间分析的好文章,为你的下一个项目提供灵感:
一有机会就去看看 Sentinel Hub,找到你需要的图片,在评论区让我知道你的想法!**
用 Python 在时间序列数据中发现季节性趋势
理解不同种类的季节性以及如何将时间序列分解为趋势和季节的指南
为什么要探索季节性?
时间序列数据中的季节性指的是以固定间隔发生的模式。这不同于有规律的周期性趋势,如股票价格的上涨和下跌,这些趋势有规律地重复出现,但没有固定的周期。从了解数据中的季节性模式中可以获得很多洞察力,甚至可以将其用作比较时间序列机器学习模型的基线。
入门
快速提示:在这篇文章中,我将使用魁北克房地产经纪人专业协会发布的数据。该协会每月发布房地产统计数据。为了方便起见,我将魁北克省和蒙特利尔大都会区的每月公寓价格中值放入一个 CSV 文件中,可在此处获得:https://drive . Google . com/file/d/1 smrkzpaa 0 AAL-zhnllfbmdgymtxgpab/view?usp =共享
了解数据是否有季节性趋势的最快方法是绘制图表。让我们看看当我们按月绘制蒙特利尔的房价中值时会得到什么。
作者图片
敏锐的眼睛可能已经从这幅图中看出,价格似乎在新年前后下降,并在几个月前夏末左右达到峰值。让我们通过为每年的一月画一条垂直线来更深入地了解这一点。
作者图片
看起来这绝对是一种趋势。在这种情况下,季节性似乎有一年的周期。接下来,我们将研究一个工具,我们可以使用它来进一步检查季节性,并将我们的时间序列分解为趋势、季节性和剩余部分。不过,在我们这样做之前,你必须了解加性和倍增性季节性之间的区别。
加法与乘法季节性
在分析时间序列数据时,您可能会遇到两种季节性。为了理解它们之间的区别,让我们看一个具有完美季节性的标准时间序列,一个余弦波:
正弦波图— 作者图片
我们可以清楚地看到,波浪的周期为 20,振幅(从中心线到波峰顶部或波谷底部的距离)为 1,并且保持不变。
附加季节性
实际时间序列很少具有恒定的波峰和波谷值,相反,我们通常会看到某种总体趋势,如随着时间的推移而增加或减少。例如,在我们的销售价格图中,中间价格往往会随着时间的推移而上升。
如果我们的季节性幅度保持不变,那么我们就有了所谓的附加季节性。下面是一个附加季节性的例子。
附加季节性— 作者图片
一个很好的思考方式是,想象我们用标准余弦波,简单地给它添加一个趋势:
作者图片
我们甚至可以把之前的基本余弦模型想象成一个趋势不变的加性模型!我们可以使用下面的简单等式来模拟加性时间序列:
Y[t] = T[t] + S[t] + e[t]
Y[t]:我们的时间序列函数
T[t]:趋势(向上或向下移动的总体趋势)
S[t】:季节性(定期出现的循环模式)
e[t]:残差(趋势或季节性中没有考虑的数据中的随机噪声
倍增季节性
您可能在时间序列数据中遇到的另一种季节性是倍增性的。在这种类型中,我们季节性的幅度根据趋势变大或变小。下面是一个倍增季节性的例子。
倍增的季节性— 作者图片
我们可以采用与加法模型类似的思路,想象我们采用余弦波,但不是将趋势相加,而是将其相乘(因此得名乘法季节性):
倍增的季节性— 作者图片
我们可以用一个类似于加法模型的等式来建模,只需将加法换成乘法。
Y[t] = T[t] *S[t] *e[t]
分解数据集
现在我们已经对不同的模型有了一个清晰的了解,让我们看看如何将我们的房地产时间序列分解成它的趋势、季节性和剩余部分。我们将使用 statsmodels 库中的季节性分解模型。
季节性分解模型要求您选择季节性的模型类型(加法或乘法)。我们将选择乘法模型,因为看起来周期的幅度随着时间而增加。这是有道理的,因为影响房价的一个重要因素是贷款利率,贷款利率是房价的一个百分比。
作者图片
哒哒!趋势、季节和残差分量作为 Pandas 系列返回,因此您可以通过调用它们的 plot()方法来绘制它们,或者对它们执行进一步的分析。可能有用的一件事是衡量它们与外部因素的相关性。例如,您可以测量趋势和抵押贷款利率之间的相关性,或者您可以查看残差和城市新生儿数量之间是否有很强的相关性。
结论
从我们的分解中,我们可以看到这个模型在季节之间获得了 5%的差异。如果你想卖掉你的房子,如果你想卖个好价钱,你应该在春末而不是仲冬上市。
寻找与网络分析的协同作用
使用 Neo4J 确定最佳神奇宝贝团队
作者图片
在本文中,我们…
使用网络分析来确定在竞争游戏中哪些人是彼此的最佳队友。
讨论衡量团队绩效和队友合作的指标。
解释从 JSON 导入数据和使用 Neo4J 执行社区检测。
标签:Neo4J,CYPHER,JSON,Pokémon,Smogon。
摘要
Smogon.com 是一个在线竞技神奇宝贝战斗的平台,它每月发布一份关于比赛数据的 JSON。这是关于电子竞技中玩家行为的大量数据,让我们能够分析竞争对手如何制定策略。在这篇文章中,我们探讨了以下问题:“我能挑选的最好的团队是什么?”一个团队由六只神奇宝贝组成。为了回答这个问题,我们从普通玩家和高排名玩家的比赛中提取数据,并比较这两个群体如何不同地选择团队。因此,我们确定了高成就玩家倾向于选择的神奇宝贝集群。虽然没有一个“最佳”团队,因为每个策略都有一个反策略,但我们可以确定高绩效球员如何选择他们的团队,我们可以确定当前竞争环境中的顶级团队。
介绍
术语“元游戏”的意思是“关于游戏的游戏”,它指的是任何类型的游戏中的竞争者如何做出战略选择,以赢得一系列比赛。这方面的例子包括大联盟棒球俱乐部如何为一个赛季挑选他们的球队,或者教练如何计划他们球队的训练制度。在每种情况下,目标都不是赢得一场比赛,而是赢得一系列比赛。
电子竞技是探索元游戏的沃土,因为它们发生在数字空间,这意味着通过正确的工具,我们可以提取游戏中发生的几乎任何事情的数据。
电子竞技的另一个有趣的特点是,游戏的开发者可以而且确实会积极干预游戏的参数,以优化游戏的“平衡”这里的“平衡”是指在一场竞争性比赛中,某些策略可能比其他策略更好。‘失衡’的结果是一个非常无聊的竞技游戏,在这里只有少数策略是可行的选项。玩家和粉丝希望游戏中有各种有趣的策略可以使用,并对抗这些策略。当游戏平衡时,就有多样性和有趣的各种比赛可以享受。
在分析元博弈时,我们可以检查可行策略的多样性,并分析玩家如何达到这些策略。从这个分析中,我们可以回答诸如“在元博弈的当前状态下,什么是最佳策略选择?”
在本文中,我们探讨了关于 Smogon.com 的元游戏的两个问题:
考察成功的球员如何选择不同于一般球员的球队。我们假设游戏中表现最好的玩家选择的队伍是“最好”的队伍。
与 2015 年相比,2020 年的高技能玩家选择团队的方式有所不同,当时 Smogon.com 以不同的方式“平衡”了元游戏。
数据
在本文中,我们使用 Smogon.com 管理的“神奇宝贝对决”的数据,通过网络分析展示了元游戏分析。
我们的目标是创建一系列网络图,其中我们显示了不同级别玩家排名中神奇宝贝被一起选中的趋势。数据中的变量总结如下:
变量
对玩家技能的衡量:在这个分析中,我们使用‘Elo’分数来评估玩家技能。下面的例子解释了 ELO 的基本概念:新玩家从 1,500 Elo 点开始。如果玩家赢得一场比赛,他们将获得 25 分以及一个可变的数额,如果他们击败的对手具有更高的 Elo 分数,则该数额会更大。相反,失败的玩家会失去 25 点 Elo 点数,如果他们输给了级别较低的对手,还会失去更多。随着时间的推移,我们希望 Elo 分数较高的玩家比分数较低的玩家更擅长赢得更多、更艰难的游戏。
对两个神奇宝贝一起被选中的一种衡量:为此,我们使用了“队友权重”,即一个神奇宝贝的选择给另一个选择的后验概率的变化。例如,如果神奇宝贝“Scizor”出现在我们数据集中 40%的团队中,但出现在所有带有“Excadrill”的团队中的 60%,那么我们可以说 Scizor 带有 Excadrill 的“队友权重”为 20。这些权重也可以是负数,这表明拥有神奇宝贝 X 的团队倾向于积极避免选择神奇宝贝 y。
数据源
上述变量的来源由 Smogon.com 提供。每个月,Smogon 都会发布一个 JSON 文件,其中包含按技能等级和游戏类型划分的数据。在我们的分析中,我们使用:
“第 8 代,过度使用”(gen8OU)游戏类型:这是最平衡的竞争阶梯。在这种游戏类型中,一些太强大的神奇宝贝是不允许的,这样玩家可以从许多可行的策略中选择,而不是被迫只选择一小撮“被压制”的选择。“第 8 代”意味着玩家可以从第 8 版之前的所有神奇宝贝中进行选择。熟悉该系列的人可能知道,每一代大约会推出 150 个新的神奇宝贝。
我们正在比较两个 JSON 数据集:平均技能等级(这是一个新手会与之竞争的)和最高技能等级。
通过比较 2015 年和 2020 年的最高技能水平,我们还可以看到策略的选择如何随着时间的推移而变化。
本文中使用的数据是开放的,可从以下网址获得:
高技能玩家:1825 年 Gen8OU+ELO,2020 年 10 月
平均技能玩家:2020 年 9 月 0-1500 ELO Gen8OU
2015 年高技能玩家:2015 年 10 月 Gen5OU at 1760+ELO
方法学
为了直观显示技能等级中的玩家如何选择他们的团队,我们创建了一个网络图,然后进行了社区分析,以确定何时某些神奇宝贝集群被一起选择到了显著的程度。为了进行这种分析,我们设置了一个 neo4j 沙箱,然后创建了一个用 CYPHER 编写的分析管道(参见附录)。
我们执行此分析的步骤总结如下:
1.我们从 JSON 导入原始数据,并为数据集中的每个神奇宝贝创建一个节点。
2.根据相同的 JSON 数据,我们在每个神奇宝贝和其他神奇宝贝之间创建了一个名为“队友”的边(即关系)。这种关系有一个浮动属性,即“队友权重”变量(参见“变量”一节)。
3.我们删除了队友权重低于任意阈值(在本例中为 40)的所有关系。这是因为很难将每个节点与其他节点相关的图形可视化,我们只对神奇宝贝很可能被一起挑选出来的关系感兴趣。
4.我们实现了 Louvain 社区检测,类似于层次聚类,以识别更频繁一起选择的神奇宝贝集合。为此,我们将队友权重变量调整为 0 到 1 之间的浮动值。
5.最后,我们用由颜色分隔的社区形象化这个图。
结果
图 1:截至 2020 年 10 月的高技能玩家。图片作者。**
在图 1 中,在高技能的玩家中,我们可以看到一些明确定义的团队起草策略。
在蓝色的中,我们有一个 12 个选项的社区,其中 cle 寓言、河马兽和 Toxapex 是最核心的。有经验的玩家可以识别出为什么这是一个强队:cle 寓言是一个强大的神奇宝贝,但对钢铁和毒药很弱。河马兽是对抗大多数钢铁和毒药的绝佳对手,包括广受欢迎的克理寓言,盔甲鸟。毒顶是一种适合对抗其他基于寓言的团队的毒药类型。
在 brown 中,Excadrill 似乎是许多团队所围绕的神奇宝贝。然而,Excardill 也可能出现在基于 cle 寓言的团队中,通常作为河马兽的替代品(因此河马兽<->Excardill 的队友权重相对较低)。
在 orange 中,Riabloom 是另一个热门的组队选择。在这个社区的左上角可以看到一个有趣的观察结果:Shuckle 似乎是 Riabloom 团队中最常见的角色,并且只有在与 Urshifu 配对时才出现。这告诉我们,在舒克尔和乌尔西弗之间可以发现一种有趣的协同作用。
绿色中,Genesect 是最中心的节点。有趣的是,没有节点将这个社区连接到其他社区,这告诉我们这个团队策略与其他选择相互排斥。
红色,我们有另一个孤立的集群,但只有三个神奇宝贝。这表明这三个经常一起出现,但他们团队中剩余的神奇宝贝是许多不同选择的混合,没有队友权重超过我们的阈值。
图 2:一般球员中的队友选择,2020 年 9 月。图片作者。**
在图 2 中,我们创建了与图 1 中相同的网络图,但是是针对普通玩家的。从图 1 和图 2 中,我们可以比较普通玩家和高技能玩家的团队选择策略。通过比较这两个数字,我们发现:
社区的分离要少得多,这意味着普通玩家更频繁地混合来自不同社区的神奇宝贝。因此,被组织成典型团队的神奇宝贝的定义不太明确。这可能表明玩家做出了更多的实验性选择,而更熟练的玩家对队友的最佳组合有更敏锐的感觉。
这些社区中最核心的节点不同于高技能层中的节点。这表明普通玩家并没有和高技能玩家组成相同的队伍,而是高技能玩家选择了和普通玩家完全不同的队伍。这告诉我们,比赛前的团队选择,而不仅仅是比赛中熟练的决定,是成功的关键因素。
图 3:高技能选手中的队友选择,2015 年 10 月。图片作者。**
比较 2020 年和 2015 年流行的团队也很有趣,当时第 6 代到第 8 代还没有出现。在图 3 中,我们为 2015 年排名靠前的玩家创建了一个网络图。从图中我们再次看到高排名的玩家比普通玩家有更清晰的社区定义。
一个有趣的观察是,尽管 cle 寓言和 Excadrill 在 2015 年都可用,但它们并不是团队建设的关键选择,就像我们在 2020 年看到的那样。这向我们表明了元博弈是如何随着时间而变化的。
结论
电子竞技中的元游戏是分析战略选择的一个极好的话题,因为我们有一个独特的机会来捕捉玩家如何在不同的战略背景下做出选择的非常详细的信息。在许多游戏中,也在许多其他环境中,单个组件如何协同工作与它们如何单独操作一样重要。这种对行动者之间协同作用的强调是分析由基因、营销活动以及游戏中队友组成的系统的重要方法。
在本文中,我们演示了如何使用共现来创建网络图,我们可以通过分析来辨别玩家采用的各种策略。我们可以识别出神奇宝贝的某些选项何时可能有互补的角色,或者何时它们服务于互斥的角色,因此玩家应该选择其中一个,而不是两个。像这样对高技能玩家行为的洞察可以帮助我们理解如何更快地在游戏中取得成功,并将这种方法应用到其他领域。
参考
https://www . smogon . com/forums/threads/everything-you-even-want-to-know-about-ratings . 3487422/
【https://www.smogon.com/stats/2015-10/chaos/gen5ou-1760.json 号
*【https://www.smogon.com/stats/2020-10/chaos/gen8ou-1825.json *
https://www.smogon.com/stats/2020-09/chaos/gen8ou-1500.json
https://en.wikipedia.org/wiki/Elo_rating_system
https://en.wikipedia.org/wiki/Louvain_method
附录:演练
您可以自己重新创建整个分析!完成下面的演练可能需要大约 20-30 分钟。这是一个初学者友好的演练,所以你不需要任何先前的经验。熟悉任何查询语言都有助于理解代码的作用。
准备一个环境
1.使用 Neo4J 创建一个免费帐户,并在此创建您自己的沙箱。
2.选择“新项目”,然后选择“空白沙盒”
3.选择“在浏览器中启动”
4.在屏幕的顶部,您会看到命令行,分块输入以下代码(不幸的是,neo4j 沙箱不够强大,无法一次执行所有代码!)
代码
分别执行每个注释部分。下面的代码从一个选定的 JSON 文件中提取数据。只需将 URL 更改为 smogon.com/stats,的不同设置,即可分析不同的技能等级或时间段。
*// Create Nodes and Relationships from JSONWITH “https://www.smogon.com/stats/2020-10/chaos/gen8ou-1825.json" AS urlCALL apoc.load.json(url) YIELD valueUNWIND value.data as dFOREACH (name in keys(d) | CREATE (Pokémon:Pokémon {id: name, teammates: keys(d[name].Teammates)}))With valueUNWIND keys(value.data) as nameMATCH (a:Pokémon) WHERE a.id = nameUNWIND a.teammates as tmMATCH (b:Pokémon) WHERE b.id = tmCREATE (a)-[r:Teammate {name: a.id +’<->’+b.id, weight: value.data[a.id].Teammates[b.id]}]->(b)// Cull Relationships where weight is below a thresholdWith 40 as thresholdMATCH p=()-[r:Teammate]->() WHERE r.weight < threshold DELETE r// Scaling weights before community detection algorithmMATCH ()-[r:Teammate]->() WITH toFloat(max(r.weight)) as maxMATCH ()-[r:Teammate]->() SET r.nweight = toFloat(r.weight) / max// Create a named graph with gdc packageCALL gds.graph.create(‘myGraph’,‘Pokémon’,‘Teammate’,{relationshipProperties: ‘nweight’})YIELD graphName// Call the Louvian community detetction algorithm on the named graphCALL gds.louvain.write(‘myGraph’, { writeProperty: ‘community’, relationshipWeightProperty: ‘nweight’ })YIELD communityCount// Name the community after most central nodeMATCH (p:Pokémon)WITH p, p.community as community, size( (p)-[:Teammate]-() ) as centrality ORDER BY community ASC, centrality DESCWITH community, (head(collect(p))).id as top, count(*) as size, collect(p.id)[0..6] as likleyTeam, collect(p) as allORDER BY size DESCFOREACH (p IN all | SET p.communityName = top)// Name the community after most central nodeMATCH (p:Pokémon)WITH p, p.community as community, size( (p)-[:Teammate]-() ) as centrality ORDER BY community ASC, centrality DESCWITH community, (head(collect(p))).id as top, count(*) as size, collect(p.id)[0..6] as likleyTeam, collect(p) as allORDER BY size DESCFOREACH (p IN all | SET p.communityName = top)// Add the community name as a label to each node, which will then color each node in the visualizationMATCH (p:Pokémon)CALL apoc.create.addLabels(p,[p.communityName]) yield node RETURN node// Before visualising, we remove the ‘Pokémon’ label, so neo4j will color code by communityMATCH (p:Pokémon)REMOVE p:PokémonRETURN p.name, labels(p)// Visualize the graphMATCH pkmn=()-[r:Teammate]->() RETURN pkmn*
寻找正确的数据分析策略
如何构建有意义的 KPI 和仪表板
KPI 是关键绩效指标的缩写。该术语指的是可用于确定公司活动绩效的关键数字。应该考虑哪些 KPI 来衡量成功或失败取决于公司目标[1]。这些 KPI 可以与其他事实和数字一起显示在所谓的仪表板上。微软 Power BI、Google Data Studio 或 Tableau 等先进的(自助式)BI 工具可用于此目的。在下面的文章中,我将描述如何战略性地开发这样的 KPI 和仪表板,以及实现这一点的两种方法。
自上而下方法
董事总经理和其他高管定义对他们来说有意义的 KPI。这些 KPI 和仪表板然后根据严格的规范实现,并且应该成为公司的准标准。
自上而下的方法流程—作者提供的图片
Pro: 流程和数字都是标准化的——这样你就知道数字是从哪里来的,可以让它们变得透明易懂。也使得部门、地区、国家具有可比性。
反对: 特殊的区域要求和环境不能或不应该被映射。
自下而上的方法
业务部门将借助自助 BI 工具构建 KPI 的任务分配给 IT 部门,或者自己使用这些工具。
通过 Google Data Studio 轻松使用 Self BI——图片由作者提供
这些不是从上面决定的,而是根据自己的需求迭代开发的。
Pro:
个别部门和地区完全可以根据自己的需求构建仪表盘。
反对:
供应可能会更加耗时,例如,可能需要提供额外的数据。此外,由于部分数据集成(尤其是仪表板的创建)没有标准化,因此很难进行比较。这也会导致更复杂的维护。
自下而上的方法流程—作者提供的图片
摘要
这两种方法在公司中经常同时出现。自下而上方法的缺点当然可以通过标准化部门中建立的 KPI 并将其推广到公司来抵消。这里的挑战是,有关各方必须就标准达成一致,但一旦达成一致,结果很可能会比自顶向下的方法更符合实际的操作需求。然而,有一点很清楚,前提是建立一个可扩展且易于使用的数据平台。有了它,这种分析首先成为可能。
“KPI 的使用意味着提高和转变组织的绩效。”― 朱【2】
资料来源和进一步阅读
[1]KPI.ORG,什么是关键绩效指标(KPI)? (2021)
[2]朱珍珠,性能大师:用整体方法开启数字性能 (2021)
查找曼哈顿每对位置之间与时间相关的旅行时间
在这篇文章中,我将向您展示一种相对简单快捷的方法,使用完全开源的软件包和开放数据来计算一天中任何时间曼哈顿每个十字路口之间的旅行时间。代码完全是用 Python 写的,可以在 GitHub 上找到。这种方法可以推广到任何有数据的城市。
纽约市的平均交通速度是每小时 4.7 英里。勒隆·皮耶特斯在 Unsplash 上的照片
作为一名交通研究人员,我经常遇到利用纽约市的出租车和叫车出行记录来测试算法和假设的研究。需要多少辆自动驾驶汽车来取代整个出租车车队?城市空中出租车机场的最佳位置是哪里?该数据集在研究社区中很受欢迎,因为它是分类的,这意味着它包括每次旅行的记录,包括确切的接送时间和地点,因此可用于非常详细和现实的研究。
来自一篇题为:出租车司机是种族主义者吗?(来源:https://bennstancil.com/nyc-taxis-and-race)
使用这些数据的挑战之一是它代表了大量的起点和终点。如果您想要测试算法,或者想要为新的假设三轮车出租车服务设置模拟,您最终需要知道所有可能的上车、下车和闲置车辆位置之间的行驶时间。这是一个多对多的旅行时间问题,计算的次数等于可能位置的个数的平方。此外,如果您想要一天中不同时间或一周中不同天的行驶时间,这意味着重新计算每个时间段的行驶时间。
使用谷歌地图 API 是一种选择,但它不是免费的,如果需要多次调用,成本会很高。像 Valhalla 这样的其他路径包是免费的,但有一个学习曲线,可能需要大量的时间来完成大规模的旅行时间计算。相反,我决定利用 Python 中相对快速的图形分析算法,以及精彩的优步运动 (UM)数据,其中包括几十个城市中曼哈顿每条道路的行驶速度。完整的方法在下一节中描述。
首先,我需要创建一个网络来代表曼哈顿的街道。幸运的是,有一个 Python 库可以解决这个问题。 OSMnx 是对现实生活中的城市进行空间分析的天赐之物,它包括一个单线功能,可以创建世界上几乎任何城市的街道网络图(见下文)。它使用 OpenStreetMap 创建图表。
import osmnx as ox
G = ox.graph_from_place('Manhattan, New York, USA', network_type='drive')
该网络包括每个街道交叉口的结点以及每条道路每个方向的边。我们现在可以使用网络算法来寻找每对节点之间的最短路径(即网络中的每个交叉点)。 NetworkX 是一个通用且功能强大的库,内置最短路径函数,是 OSMnx 的构建模块之一。我们可以使用以下代码行创建一个 shortest_path 生成器:
import networkx as nx
path_enumerator = nx.shortest_path(G, weight='weight')
然后我们可以通过调用path_enumerator[origin][destination]
找到包含任意节点对之间最短路径的边集。我们还可以使用单独的函数为最短路径的创建一个生成器:
*path_generator = nx.shortest_path_length(G, weight='weight')*
但是在这种情况下“最短”是什么意思呢?您会注意到,该函数采用一个“权重”输入参数,该参数可用于指定在确定“最短”路径时使用哪些属性。现在,我们的边包括距离属性,但没有旅行时间。
OSMnx 确实包括一个单独的功能来分配网络中每个链接的旅行时间,但它们是基于 OpenStreetMap 的自由流旅行速度。在曼哈顿几乎没有自由流动的流量,所以这对于大多数应用程序来说是行不通的。幸运的是,OSMnx 保留了网络中每条边的 OSM 路 ID 作为边属性。猜猜 OSM 路 ID 还索引了什么?UM 速度数据。我们需要做的就是导入 UM 数据,将速度作为一个新属性附加到每条边上,然后使用速度作为最短路径算法的权重。
UM 数据可以从网站上以 CSV 格式下载。下面是一个例子,说明如何使用 Python 从 CSV 导入 UM 数据,并使用方式 id 作为键,速度作为值创建一个字典。
*import pandas as pd
df = pd.read_csv('Data/nyc_avg_speeds_2019-06.csv')
mydict = dict([(t.osm_way_id, t.speed) for t in df.itertuples()])*
现在,我们可以快速找到曼哈顿任何两个地点之间在任何时间段或任何感兴趣的一天的最短驾驶时间。如果使用滑行数据,请注意,OSMnx 包括将任何纬度/经度对捕捉到最近的图形节点的功能:
*pickup_node = ox.get_nearest_node(G, (lon, lat))*
这种方法不仅限于曼哈顿。OSMnx 覆盖了全球大部分地区,而 UM 包括了不同大洲的许多城市,因此它也可以用于开罗、悉尼或班加罗尔。
我希望这能对你有所帮助。如果你在自己的研究中使用这个作为资源,请让我知道。
[1]从 2016 年 6 月开始,这些位置实际上被汇总到了社区级别,在此之前,一些聪明人发现你可以使用准确的位置数据来跟踪城市中的名人,并确定脱衣舞俱乐部顾客住在哪里。
[2] UM 速度数据基于优步驾驶员记录的行驶速度,可用于一周中任意一天或多天的 5 个时间段。
[3] OpenStreetMap 数据是 OpenStreetMap 贡献者。
在被低估的足球运动员中发现未开发的潜力
世界级的足球运动员收入丰厚。
维也纳·雷耶斯在 Unsplash 上拍摄的照片
不出所料,世界级的足球运动员收入不菲。
据美国经济杂志 Forbes 报道,2020 年,阿根廷足球运动员莱昂内尔·梅西以 1.26 亿美元的收入排名世界第一。我使用了国际足联数据集中的统计元素来探究这些元素是如何影响球员工资的。我从 Kaggle 得到了 FIFA 数据集。
来自 Kaggle 的 FIFA 数据集
然后我分析了相对于能力被低估的球员(相对于能力领取低工资)。
换句话说,该分析的目标是
- 根据球员 2020 年的特征数据预测 2021 年的工资,并模拟其与 2021 年实际工资的匹配程度
- 预测与他们的特征元素相比目前被低估的未来足球明星。
[目标# 1——根据球员 2020 年的特征数据预测 2021 年的工资,并模拟其与 2021 年实际工资的匹配程度]
数据清理
有 65 个特征,但是我删除了具有“对象”类型和“标记”列的特征(由于大量的空值)。
为了从工资和价值列中删除“€”、“K”、“M”,我创建了几个函数来清理单词,如下所示。此函数还将“工资”和“价值”列的类型更改为 float,然后乘以 1,000,000 而不是“M”,乘以 1,000 而不是“K”。
用于删除字符串并将字符串数据转换为数字数据的函数
使用创建的函数清理数据(11,779 行和 47 列)
然后,我可视化了 Wage_2021(€)的信息,这是预测的目标。
直方图和箱线图
似乎有太多的局外人,因为著名的明星球员拿着巨额工资。
在这些特性中,我删除了“ID”和“Name”列,只选择数字数据,并为每个特性创建了直方图以便可视化。
每个特征的直方图
从直方图中,我意识到这些特征没有被缩放。所有要素都应进行归一化,以符合相同的单位。
我使用了来自 Scikit-learn 库的 StandardScaler() 。
首先,由于我使用原始值来预测工资,“Wage_2021(€)”应该从标准化中排除。
我设置w 2020 _ 21 _ picher . drop([' Wage_2021(€)'],axis = 1)为 X 使用除 Wage _ 2021(€)以外的所有特性,然后使用 StandardScaler()。fit_transform()归一化所有要素。
完成这项工作后,所有缩放后的特征通过 pd.concat 函数与“Wage_2021(€)”的原始值相结合。最后,我将 Wage_2021(€)设为 y 进行线性回归。
所有特征都被规范化,如下所示。(y:工资 _2021(€))
数据帧' picher_df '
线性回归
对于线性回归,我将数据分为训练数据集和测试数据集。
为了评估该回归模型,使用了 R2 评分和RMSE 评分。
R2 分数和 RMSE 分数
然后,我训练并输出回归系数。打印出回归系数后,我想知道这 45 个特征中哪一个是最有影响的特征,于是我用 statsmodel 库进行了回归分析。我将结果可视化如下。
然后我创建了一个热图来进行关联分析。
首先,我计算了特征之间的相关系数矩阵,并用计算值生成了一个热图。
热图—相关系数矩阵
我检查了系数的多重共线性,作为提高回归预测性能的一种方法。
一般来说,如果 VIF 系数超过 10-15,就意味着出现了多重共线性问题。
VIF 系数
基于这个结果,我选择了
['弱脚','国际声誉','技能招式','工资 _2020(€)','沉着','价值 _2020(€)','年龄','潜力','最佳综合评分','总体'] 作为有效特征。
从 VIF 因子的得分来看,多重共线性问题似乎发生在最佳总体评分(99.64)和总体评分(102.49)中。
我不得不删除“最佳总体评分”或“总体”来解决多重共线性问题,
当我在删除“总体”后再次计算系数的多重共线性时,另一个系数(“最佳总体评级”)从 99.64 更改为 7.73。
“最佳总体评价”从(99.64)变为(7.73)
完成这项工作后,我用选定的功能重置了 X。
然后用 R2 分数和RMSE 分数再次评估回归模型。
具有选定 VIF 系数的 R2 评分和 RMSE 评分
第一次得分与第二次得分的比较
可视化
具有选定特征的 X(['弱脚','国际声誉','技能移动','工资 _2020(€)','沉着','价值 _2020(€)','年龄','潜力','最佳综合评分']),
我用predict _ 2021 _ wage = lr . predict(X)预测了 2021 年的工资。然后将‘预测 _ 2021 _ 工资’和‘工资 _ 2021(€)’与 picher_df 结合。
连接数据框后,我将列‘y’重命名为‘real _ Wage _ 2021’,****‘Wage _ 2020(€)’重命名为‘real _ Wage _ 2020’。
并且只分析了续约后工资有变化的球员。
结果 _df:
结果可视化 _df:
用 Matplotlib 可视化
数据机器人可视化
【目标 2——预测与他们的特征元素相比目前被低估的未来足球明星。]
Andriyko Podilnyk 在 Unsplash 上拍摄的照片
为了找出那些年轻、身体状况良好但被低估的球员(目前工资较低,因此将有利于俱乐部),我重新加载了数据集,并使用了从系数的多重共线性中选择的列。对于守门员的数据集,我添加了[' GK driving ',' GKHandling ',' GKKicking ',' GKPositioning ',' GKReflexes']列,这是专门为守门员提供的。
我用 75% 作为条件的值来计算被低估的玩家。
对于年龄,我使用 25%的值作为标准,而不是 75%的值。这是因为与其他属性不同,年龄越小越好。此外,我没有使用工资和价值列,因为工资和价值应该在其他功能设置为确定的标准后进行评估。
用于生成描述性统计数据的描述函数
年龄使用 25%,其他特征使用 75%
以上所有条件,球员有 92 个结果,门将球员有 8 个结果。
我按照工资 _2021(€ 一栏升序排列结果。
92 名被低估的球员
8 名被低估的门将球员
从结果来看,我发现 92 名球员和 8 名门将的能力被低估了。
结论
总之,从 Kaggle 数据集中有超过 50 个关于足球运动员的统计特征。基于数据集使用线性回归模型预测足球运动员的未来工资,在评价中显示出相当高的分数。
此外,VIF 系数有助于挑选最有用的特征。基于这些具体特征,用 describe 函数算出前 25%的数据,就能算出相对于能力被低估的球员。
根据结果,包括 N. Zaniolo、J. Kluivert、L. Ivanuš ec 和 A. Hlož ek 在内的 92 名球员与其能力相比被低估。8 包括 Pau López、D. Livakovi、A. Onana 和 P. Rajkovi 在内的守门员球员与其能力相比也被低估。
如果假设这些特征是基于真实球员的信息进行客观评估的,这些有天赋的年轻球员是转会市场上值得关注的人。
在 Python 中使用 TF-IDF 和余弦在术语上下文矩阵中从头开始查找单词相似度
嵌入是直接从单词在文本中的分布来表征单词的意思。这些表示被用在每一个利用意义的 NLP 应用中。
这篇文章的完整代码可以在这里找到。
词义的一个重要组成部分是词义之间的关系。例如,当一个单词的意思与另一个单词的意思相同或几乎相似时,我们说这两个单词的两个意思是同义词。如的关键 / 的命令式。
虽然单词没有很多同义词,但大多数单词都有很多相似的术语。饭不是豆的同义词,但是饭和豆无疑是相近的词(都是食物)。在谈论词义之间的关系时,相似性是从同义词的一个有价值的转变;这将简化我们的任务。
我们将分析一系列莎士比亚的文本,并在我们的戏剧中寻找戏剧和文字之间的相似之处。我们的数据有一些来自不同莎士比亚戏剧的句子和戏剧的名字。
术语-文档矩阵
意义的向量或分布模型通常基于共现矩阵,这是一种表示单词共现频率的方法。我们将实现两个流行的矩阵;术语-文档矩阵和术语-上下文矩阵。
在术语-文档矩阵中,每行代表词汇表中的一个单词,每列代表文档集合中的一个文档。请看下面我们的实现:
def term_document(self, word_list):
for play, word in word_list:
if (play, word) in self.term_document_matrix:
self.term_document_matrix[(play, word)] += 1
else:
self.term_document_matrix[(play, word)] = 1
return self.term_document_matrix
我们矩阵中的数据示例如下:
('Twelfth Night', 'love'): 77
('Julius Caesar', 'come'): 75
('Romeo and Juliet', 'enter'): 74
上面的意思是单词 enter 在戏剧《罗密欧与朱丽叶》的句子中出现了 74 次,以此类推。
我们可以从上面的矩阵中计算出这些剧本之间的相似性,这可以使用余弦来完成。这基于线性代数中的点积运算符,可计算如下:
图片来自作者
余弦值的范围从指向相同方向的向量的 1 到正交向量的 0。
我们将利用 scipy 的空间库来实现这一点,如下所示:
def cos_sim(self, vector1, vector2):
cosine_similarity = 1 - spatial.distance.cosine(vector1, vector2)
print(cosine_similarity)
我们可以通过一个小样本轻松验证这一点:
图片来自作者
实现此功能以进行测试:
**apricot** = [1, 0, 0]
**digital** = [0, 1, 2]
**information** = [1, 6, 1]
print(self.cos_sim(apricot, digital))0.0
测试其他样本也返回有效结果,太好了,现在让我们测试我们的数据,我们将相互比较我们的每个文档:
def cal_cosine(self, docs):
tf = self.read_csv()
play_dict = {}
for play in self.play_names:
play_vec = []
for word in self.vocab:
play_vec.append(tf[(play, word)])
play_dict[play] = play_vec
scores = []
for k1, v1 in play_dict.items():
for k2, v2 in play_dict.items():
if k1 <= k2: continue
scores.append((self.cos_sim(v1, v2), (k1 ,k2)))
scores.sort(reverse=True)
print(scores[:25])
我们的顶级余弦相似点是:
(0.9885556994486011, ('Cymbeline', 'A Winters Tale')),(0.9817079988849085, ('Henry VI Part 2', 'Henry VI Part 1')),(0.9811981513422073, ('Alls well that ends well', 'A Winters Tale'))
术语上下文矩阵
对于我们上面的计算,我们使用了频率,但原始频率可能会非常倾斜,要知道我们的单词或文档共享哪些上下文,停用词在这里或任何其他频繁出现的单词形式都没有用,不知何故,在你关注的单词附近出现的单词的频率更重要。
这个问题的解决方案是使用 tf-idf 加权,这是两项的乘积:
TF——这是词频,即单词 t 在文档 d、中的出现频率,这是在日志空间中计算的:
图片来自作者
IDF -本逆文档频率N/df;其中 N 是集合中的文档总数,df 是一个术语出现在其中的文档数。这使得只在少数文档中出现的单词具有更高的权重。仅限于几个文档的术语有助于将这些文档与集合中的其他文档区分开来。术语出现的文档越少,权重越高,这也是在日志空间中计算的:
图片来自作者
TF-IDF 是 TF 和 IDF 的点积,因此计算为:
图片来自作者
让我们在当前的语料库上尝试一下,我们将从实现一个术语上下文矩阵开始,我们将查看每个单词和前后的 4 个单词,然后统计它在同一个单词周围出现的频率。
def term_context(self):
term_context = defaultdict(lambda: defaultdict(lambda: 0))
with open("ShakespearePlays_text.csv", "r") as f:
# load csv
reader = csv.reader(f, delimiter=";")
# loop through line in csv
for line in reader:
play_name = line[1]
if play_name not in self.play_names:
continue
tokens = line[5].split()
sentence = []
for term in tokens:
token = self.clean(term)
if token in self.vocab:
sentence.append(token)
for i in range(len(sentence)):
word = sentence[i]
for j in range(max(0, i - 4), min(len(sentence), i + 5)):
if i == j: continue
term_context[word][sentence[j]] += 1
return term_context
我们的术语上下文矩阵看起来像这样:
'**befortune**': ({'i': 1, 'wish': 1, 'all': 1, 'good': 1, 'you': 1})'**bohemia**': ({'chance': 1, 'camillo': 1, 'to': 4, 'visit': 1,'on': 1, 'difference': 1, 'betwixt': 1, 'our': 1, 'and': 5, 'your': 1, 'sicilia': 1, 'means': 1, 'pay': 1, 'the': 5, 'visitation': 1}
接下来,我们将构建我们的文档频率矩阵,我们将使用上面的术语上下文来完成这个任务,(以减少计算时间并使用更小的子集),
def cal_doc_freq(self, term_frequency):
values_per_key = {}
for k, v in term_frequency:
values_per_key.setdefault(k, set()).add(v)
counts = {k: len(v) for k, v in values_per_key.items()}
return counts
我们将使用下面的公式计算术语上下文中所有单元格的文档频率:
图片来自作者
我们将计算 TF-IDF
t = self.read_csv()
counts = self.cal_doc_freq(t)
tc = self.term_context()
for i in tc:
for j in tc[i].keys():
tc[i][j] = tc[i][j] * (1 / counts[j])
return tc
我们将在我们的 vocab 的一个小子集上进行测试,并找到单词罗密欧、朱丽叶、贵族、凯撒和朋友与其他单词的相似性。
def compute_word_similarity(self, words):
tc = self.idf()
def to_vec(w):
vec = []
for x in self.vocab:
vec.append(tc[w][x])
return vec
for word in words:
word_vec = to_vec(word)
scores = []
c = 0
for k in tc.keys():
if k == word: continue
k_vec = to_vec(k)
scores.append((self.cos_sim(word_vec, k_vec), k))
c += 1
# if c > 10: break
scores.sort(reverse=True)
print("Top-5 matches for " + word + ": ", scores[:5])
我们的前 5 个相似词是:
**Top-5 matches for romeo**: [(0.7349592582145151, 'dead'), (0.7291389527324256, 'he'), (0.7256033280986567, 'then'), (0.7237096963536124, 'it'), (0.719416236702853, 'where')]**Top-5 matches for juliet**: [(0.7840722487008701, 'lucius'), (0.7700540752904482, 'servants'), (0.7692483251584336, 'soldiers'), (0.7682255792237922, 'warwick'), (0.7672900349518263, 'others')]**Top-5 matches for nobleman**: [(0.8139265551526883, 'woman'), (0.813455008644156, 'soldier'), (0.808373550553078, 'little'), (0.8053083580334184, 'gentleman'), (0.8046068607590102, 'stranger')]**Top-5 matches for caesar**: [(0.8897940437391335, 'him'), (0.8825311102107262, 'them'), (0.8718307075270313, 'that'), (0.8707738937545483, 'his'), (0.8674185090147457, 'me')]**Top-5 matches for friend**: [(0.9280138220686541, 'wife'), (0.9239327316145367, 'daughter'), (0.9111186066627961, 'father'), (0.9091224168395339, 'brother'), (0.9086148854991047, 'mother')]
这看起来很合理,因为朋友——妻子、女儿、兄弟、父亲和母亲确实有一些相似之处。贵族和绅士或许还有士兵有一些相似之处,等等。
我确信有办法让我们的预测更准确,但这是一个好的开始。
期待问题、评论和反馈。谢了。
使用 Networkx 在 Spotify 上查找下一位最喜欢的艺术家
你现在最喜欢的艺术家会如何影响你对新音乐人才的追求?
安托万·朱利安在 Unsplash 上拍摄的照片
一年来,我一直在查看 Spotify 的 Discover Weekly,尽管我很欣赏他们的选择,但我发现自己在推荐的 30 首歌曲中,最多只喜欢 5 首。我喜欢的那些人的共同点是,我会点击他们背后的艺术家的简介,阅读他们的简历,并查看他们的一些热门歌曲。
我意识到比起发现歌曲,我更喜欢发现艺术家。
我知道宝石是稀缺的,一个艺术家很少会有一首以上的热门歌曲,但有时一首歌并不能涵盖一个艺术家的全部,我们错过了探索他们的唱片目录的机会。
本文探讨了一种基于你的历史流媒体偏好在 Spotify 上寻找新艺术家的策略。每一步都伴随着一个使用 Spotify API 的 Python 实现。
下图是司徒迈(比利时艺术家)在 Spotify 上的个人资料页面。点击“粉丝也喜欢”,根据对 Spotify 社区收听历史的分析,你会找到多达 50 位与司徒迈相似的艺术家的列表。API 文档没有深入到相似性度量的细节,但我认为它是音乐特征和协作过滤的结合(即,如果两个艺术家拥有相同的粉丝群,那么他们很可能是相似的)。
Spotify 上的司徒迈个人资料(信用:https://www.spotify.com)
“粉丝也喜欢”列表不够翔实,因为它只显示了与司徒迈相似的艺术家,而没有考虑我个人的历史流媒体偏好。换句话说,如果能知道“粉丝也喜欢”页面上的艺人和我的前 50 名歌手有多相似,那就更有帮助了。
与司徒迈相似的艺人名单(鸣谢:https://www.spotify.com)
例如, Black M 被认为是第四个与司徒迈相似的人物,但我很想知道,在我的年度前 50 名艺术家中,有多少人与 Black M 有关
第一步:检索 Spotify 流媒体数据
在 Spotify 上为开发者创建一个账户后,您将收到一个 API 令牌来访问您的流媒体历史记录。
Spotify 在三个不同的时间范围内跟踪您的前 50 位艺术家:
- 短期:基于你上个月的流媒体
- 中期:基于你过去六个月的流水
- 长期:自你的 Spotify 账户创建以来
我们编辑了以下三个时间范围内的顶级艺术家列表:
第二步:创建一个你最喜欢的艺术家的网络
网络说明了我喜欢的艺术家是如何联系在一起的。大节点是我的前 50 名艺术家,小节点是与他们相关的其他艺术家。请注意 Black M 与我已经喜欢的 4 位艺术家联系在一起,这意味着我应该探索他的音乐,尽管就与司徒迈的相似性而言,他似乎是第四位。
Spotify 上我最喜欢的艺术家的网络可视化
第三步:排列艺术家
与我的前 50 名联系最多的艺术家列表
按照同样的逻辑,我们统计网络中每个艺术家的学位,然后排除前 50 名的艺术家。结果是一个表格,显示了与我的前 50 位艺术家联系最多的艺术家。艺术家之间的联系越多,我就越有可能觉得他们的音乐有趣,值得探索。
注: 我恰好只知道这一张表中 30%左右的艺人。但看到他们与我的前 50 名艺术家有如此紧密的联系还是很有趣的。
在 Spotify 上包含这一功能将允许用户根据他们的流媒体偏好发现更丰富的艺术家网络,这将改善我们的音乐发现体验,并让艺术家对他们的整个作品给予相当多的关注。
在机器学习中找到自己的位置
为什么以及如何找到“你的”领域
蒂姆·福斯特在 Unsplash 上的照片
机器学习可能会让人不知所措。我和我公司的一位研究科学家(也就是博士)聊过,她提到她对自己的 ML 技能感到不自信。有这么多事情要做。每天都有很多东西要学。这种感觉与你所处的职业阶段无关。无论你是刚开始,在读研,还是已经在这个行业工作。在职业生涯的任何阶段,你都需要有自己的定位或“自己的领域”。
首先,让我们试着理解为什么拥有自己的利基市场是重要的,并有助于导航 ML 职业选择。
在线课程不会增加价值
在线课程会增加你个人知识的价值,但不会增加你简历的价值。
从今天开始,每个人都在 Coursera 课程中构建图像检测分类器。
把它放在你的简历上不会增加多少价值。在学习方面,这些课程是结构化的,有利于起步。但是,最终,你需要建立自己的东西来更好地理解这个话题,并在面试中获得优势。
利基帮助你筛选研究生院和工作
我经常被问到这个问题-
我如何决定申请哪所研究生院?
按主题过滤永远是我的答案。大多数大学针对某一特定主题开设了范围广泛的课程。确保根据你的兴趣进行筛选。看看提供的课程,检查它们是否是你感兴趣的(因为你将投入大量时间学习这些)。
这也有助于筛选出你“适合”的工作类型,增加你被录用的机会。
帮你回答你在做什么?
在大多数面试中,我被问到的第一个挥之不去的问题是:你从事什么工作?
如果一个人从事过 10 个不同的主题,并且对每个主题都了如指掌,他该如何回答这个问题呢?
大多数面试官喜欢深入你的一个项目,并在面试的剩余时间谈论它。
例如,当我面试各种角色时,我在多模态学习和图形神经网络方面的经验帮助我获得了目前的角色,尽管我的工作与这些领域没有直接关系。
利基最终成为你的技能
今天每个人都是数据科学家。让你与众不同的是你的专业。如果一个人除了 ML 中的基本主题之外还知道主动学习,他可以在那个特定的领域使团队受益。它把你和其他人区分开来。所有关于这个特定领域的问题都会直接指向你,这有助于在你的团队中建立信任。
既然你已经有点确信为什么找到你的专业领域是重要的,那么让我们看看人们如何找到“他们的”?哈佛大学的助理教授伊马·拉卡拉朱博士在最近的一次采访中说
在 ML 中寻找最好的主题就像是在问我是否有办法优化我的生活(或我的研究主题)从而赢得图灵奖?简单的回答是号
在这样一个快速发展的领域中,没有办法将你的主题优化到最令人兴奋的一个,这个主题在几年后仍然有用。趋势会随着时间而变化,这是一个持续的学习过程。但这是我多年来遵循的原则。
- 获取主题列表- 您可以从研讨会、教程和会议中找到当前的【热门】主题。举个例子,今年我去了 ICML,我做的第一件事就是查看所有正在进行的研讨会和辅导课。工作坊通常展示未发表的作品,对于了解未来趋势非常有用。
- 从教程中学习- 我认为进入主题的最佳方式之一就是从教程中学习。它们为正在进行的研究和之前完成的工作提供了一个很好的时间表。
- 寻找代码实现- 我找到了该领域中广泛使用的库,并尝试了一些基本代码。然后我试着浏览一些基础论文的研究实现。这是非常个人化的,但是直到我做了这些,我对了解主题的实际工作流程并不感到完全满意。很明显,如果你从事理论方面的工作,这就不同了。
- 第一个项目——找到该领域最基本的问题,并实施。这有助于更好地了解问题的设置,并让您的手接触代码。假设您想深入研究图形神经网络。尝试访问广泛使用的图形数据,并在 Numpy 或 Torch Geometric 中构建最简单的 GNN。
- 开始建立关系网- 最好的学习方法是向专家学习。联系现场的人,问他们相关的问题。也就是说,不要发送普通邮件和垃圾邮件,这对任何人都没有帮助。没有人回复垃圾邮件。你可以问一些问题,比如~‘你能评论一下这个领域的范围吗?’。“这个话题在行业中有哪些应用”,“你提出的方法的最小扩展是什么?”、‘关于这个话题,你最喜欢的论文是什么?’
- Post starting up- 现在,有了你所学的一切,你就可以提出自己的想法并付诸实施了。
微调用于语法纠正的转换器模型
学习如何训练一个名为 T5 的转换器模型成为你自己的语法校正器
作者图片
在本文中,我们将讨论如何训练一个最先进的转换器模型来执行语法纠正。我们将使用一个名为 T5 的模型,它目前在通用语言理解评估(GLUE)基准上的表现优于人类基准,使其成为现有的最强大的 NLP 模型之一。T5 由 Google AI 创建,并向全世界发布,供任何人下载和使用。
在本教程中,我们将使用我自己的 Python 包 Happy Transformer 。快乐变形金刚建立在拥抱脸的变形金刚库之上,只需几行代码就可以轻松实现和训练变形金刚模型。因此,理解本教程的内容不需要对 NLP 或 Python 有复杂的理解,即使我们将训练世界上最有能力的人工智能模型之一。
向下滚动到“预训练模型”部分,了解如何下载和使用我训练并上传到 Hugging Face 的模型分发网络的语法纠正模型。
装置
快乐变压器在 PyPI 上可用,因此可以 pip 安装。
pip install happytransformer
模型
T5 有几种不同的尺寸,我们将使用基本模型,它有 2.2 亿个参数。最大的可用模型有 110 亿个参数,而最小的有 6000 万个参数。
T5 是一个文本到文本的模型,意味着给定的文本,它根据输入生成一段独立的文本。因此,我们将从 Happy Transformer 导入一个名为 HappyTextToText 的类,我们将使用它来加载模型。我们将为第一个位置参数提供模型类型(T5 ),为第二个位置参数提供模型名称(t5-base)。
from happytransformer import HappyTextToText
happy_tt = HappyTextToText("T5", "t5-base")
数据收集
我们将使用一个名为 JFLEG 的著名数据集来训练该模型。根据其拥抱脸页面上的描述,它是“开发和评估 GEC 系统流畅度的黄金标准基准”(GEC 代表语法错误纠正。)此外,根据谷歌学术的说法,它的论文目前有 106 次引用,这表明它在 NLP 社区内确实受到尊重[1]。它受 CC BY-NC-SA 4.0 许可证的约束,这意味着您必须提供其归属,不得将其用于商业目的,并对任何衍生应用相同的许可证*。
*这不是法律建议。阅读 完全许可 了解更多信息
该数据集在 Hugging Face 的数据集分发网络上可用,并且可以使用他们的数据集库来访问。因为这个库是 Happy Transformer 的依赖项,所以我们不需要安装它,可以直接从库中导入一个名为 load_dataset 的函数。
from datasets import load_dataset
数据集的 id 是“jfleg ”,有两个分支“"validation”和“测试”我们将验证集用于训练,测试集用于评估。
train_dataset = load_dataset("jfleg", split='validation[:]') eval_dataset = load_dataset("jfleg", split='test[:]')
数据检查
我们刚刚成功下载了数据集。现在让我们通过迭代一些案例来探索它。训练和评估数据集都以相同的方式构造,并且具有两个特征,句子和修正。句子功能包含每个案例的单个字符串,而更正功能包含 4 个人工生成的更正列表。
for case in train_dataset["corrections"][:2]:
print(case)
print(case[0])
print("--------------------------------------------------")
结果:
【所以我认为如果我们的祖先没有发展科学技术,我们就不会活着……】
所以我认为如果我们的祖先没有发展科学技术,我们就不会活着。
— — — — — — — — — — — — — — — — — — — — — — — — —
[‘不适用于汽车’,‘不要在车里使用。’,'车不能用',‘不能用这辆车。’】
不适用于汽车。
— — — — — — — — — — — — — — — — — — — — — — — — —
数据预处理
现在,我们必须将处理成 Happy Transformer 的适当格式。我们需要将训练和评估数据组织成相同的格式,这是一个包含两列的 CSV 文件:输入和目标。输入列包含语法不正确的文本,而目标列包含来自目标列的文本的正确版本。
下面是将数据处理成适当格式的代码。我们必须通过给每个输入添加相同的前缀来指定我们希望执行的任务。在这种情况下,我们将使用前缀“grammar:”。这样做是因为 T5 模型能够用单个模型执行多项任务,如翻译和总结,并且为每项任务使用唯一的前缀,以便模型学习执行哪项任务。我们还需要跳过包含空白字符串的情况,以避免微调时出现错误。
import csv
def generate_csv(csv_path, dataset):
with open(csv_path, 'w', newline='') as csvfile:
writter = csv.writer(csvfile)
writter.writerow(["input", "target"])
for case in dataset:
# Adding the task's prefix to input
input_text = "grammar: " + case["sentence"]
for correction in case["corrections"]:
# a few of the cases contain blank strings.
if input_text and correction:
writter.writerow([input_text, correction])
generate_csv("train.csv", train_dataset)
generate_csv("eval.csv", eval_dataset)
我们只是生成我们的训练和评估数据!我们总共生成了 3016 个训练样本和 2988 个评估样本。
培训前评估
我们将使用一个称为损失的通用指标来评估微调前后的模型。损失可以描述为模型的预测与正确答案相比有多“错误”。因此,如果微调后损失减少,那么这表明模型学习了。重要的是,我们使用单独的数据进行训练和评估,以表明该模型可以概括其获得的知识,以解决看不见的情况。
你还可以使用其他指标来评估语法纠正模型。其中最流行的一个叫 GLEU,在这里可以了解更多https://www.researchgate.net/publication/283810389_Ground_truth_for_grammatical_error_correction_metrics【2】。Loss 是用 Happy Transformer 实现的最简单的方法,所以我们将使用它。
让我们在任何训练之前确定评估数据集上的模型损失。为此,我们将调用 happy_tt 的 eval()方法,并提供包含评估数据的 CSV 路径。
**before_result = happy_tt.eval("eval.csv")**
结果是一个 dataclass 对象,它只有一个名为 loss 的变量,我们可以如下所示对其进行隔离。
**print("Before loss:", before_result.loss)**
结果:亏损前:1 . 54385 . 38383838661
培养
现在让我们训练模型。我们可以通过调用 happy_tt 的 train()方法来实现。为了简单起见,我们将使用默认参数,而不是批量大小,我们将把批量大小增加到 8。如果您遇到内存不足的错误,那么我建议您减少批量大小。您可以访问此网页了解如何修改各种参数,如学习率和时期数。
**from happytransformer import TTTrainArgs args = TTTrainArgs(batch_size=8) happy_tt.train("train.csv", args=args)**
培训后评估
像以前一样,让我们确定模型的损失。
**before_loss = happy_tt.eval("eval.csv") print("After loss: ", before_loss.loss)**
结果:损失后:0 . 54687 . 68686868661
这就对了,你可以看到损失减少了!但是,现在让我们通过提供示例来更定性地评估该模型。
推理
现在让我们用这个模型来纠正我们将提供的例子的语法。为此,我们将使用快乐 tt 的 generate_text()方法。我们还将使用一种称为波束搜索的算法进行生成。您可以在这个网页上查看您可以修改的不同文本生成参数,以及您可以用于通用算法的不同配置。
**from happytransformer import TTSettingsbeam_settings = TTSettings(num_beams=5, min_length=1, max_length=20)**
示例 1
**example_1 = "grammar: This sentences, has bads grammar and spelling!" result_1 = happy_tt.generate_text(example_1, args=beam_settings) print(result_1.text)**
结果:这个句子有糟糕的语法和拼写!
示例 2
**example_2 = "grammar: I am enjoys, writtings articles ons AI." result_2 = happy_tt.generate_text(example_2, args=beam_settings) print(result_2.text)**
结果:我喜欢写关于人工智能的文章。
后续步骤
有一些方法可以潜在地提高性能。我建议将一些评估案例转移到训练数据中,然后通过应用网格搜索之类的技术来优化超参数。然后,您可以将评估案例包括在训练集中,以使用您的最佳超参数集来微调最终模型。
我还建议您应用基本的数据预处理。数据集中的某些案例包含多余的空间,如果不进行更正,模型将在不需要的时候生成空间。因此,您可以应用下面的代码来更正训练和评估数据的输入和输出文本。
**replacements = [
(" .", "."),
(" ,", ","),
(" '", "'"),
(" ?", "?"),
(" !", "!"),
(" :", "!"),
(" ;", "!"),
(" n't", "n't"),
(" v", "n't"),
("2 0 0 6", "2006"),
("5 5", "55"),
("4 0 0", "400"),
("1 7-5 0", "1750"),
("2 0 %", "20%"),
("5 0", "50"),
("1 2", "12"),
("1 0", "10"),
('" ballast water', '"ballast water')
]
def remove_excess_spaces(text):
for rep in replacements:
text = text.replace(rep[0], rep[1])
return text**
现在,在 generate_csv()函数的底部进行以下更改。
**input_text = remove_excess_spaces(input_text)
correction = remove_excess_spaces(correction)
writter.writerow([input_text, correction])**
最后,您可以保存您的模型,并在其他时间加载它,如本网页所述。
测试你的技能:
你可以微调一个语法纠正模型,上传到 Hugging Face 的模型分发网络,增强学习。特别是,我建议你考虑使用谷歌新发布的语法纠错数据集,名为 C4_200M 语法纠错合成数据集 [3]*。然后,跟随这个教程在你训练完一个模特后,如何上传一个模特到拥抱脸的模特分销网络。
如果您使用本教程中讨论的技术发布了一个模型,请给我发电子邮件(eric@vennify.ca)。我可能会发表一篇如何使用它的文章。
*许可证: 知识共享署名 4.0 国际
预训练模型
我在 Hugging Face 的模型发布网络上发布了一个模型,使用了本教程中介绍的数据集和技术。我还应用了后续步骤部分中的建议。我在下面包含了演示如何使用它的代码。
**happy_tt = HappyTextToText("T5", "vennify/t5-base-grammar-correction")
result = happy_tt.generate_text("grammar: I boughts ten apple.", args=beam_settings)print(result.text)**
结果:我买了十个苹果。
结论:
我希望你把你学到的东西应用到训练你自己的模型上,然后通过在拥抱脸的模型发布网络上发布给全世界。通过这样做,您将帮助许许多多渴望实现高质量语法纠正模型的人。或者,您可能只是滚动到本文的底部,以了解如何实现预训练模型。无论如何,希望你学到了有用的东西,并保持快乐!
资源
快乐变形金刚的 GitHub 页面
订阅我的 YouTube 频道观看即将发布的语法纠正视频。
加入 Happy Transformer 的 Discord 社区进行交流,并向阅读过这篇文章并对 NLP 充满热情的人提问
本教程中使用的代码
参考
[1] C .纳波莱斯,k .坂口,j .泰特劳特, JFLEG:一个流利度语料库和语法纠错的基准,EACL 2017
[2] C .纳波莱斯,k .坂口,m .波斯特,j .泰特劳特,语法纠错度量的基础真理,IJCNLP 2015
[3] F. Stahlberg,S. Kumar,利用标记的讹误模型进行语法纠错的合成数据生成,ACL 2021
原载于 2021 年 8 月 18 日https://www . venni fy . ai。**
针对情感分类任务微调“LaBSE”
一些背景
多语言语言模型(让我们称之为“MLM ”)由于其提供多语言单词嵌入(或句子、文档等)的能力,近来已经成为 NLP 领域的趋势。)在单个模型内。“预训练”是与 MLMs 一起出现的另一个术语,它告诉我们,模型已经在不同领域的大型语料库上训练过,因此我们不必从头开始再次训练它们,但我们可以针对所需的目标任务“微调”它们,同时利用来自预训练知识的“知识转移(转移学习)”。传销主要由谷歌、脸书、百度等科技巨头发布供公众使用,因为他们有资源来训练这些具有数百万、数十亿甚至数万亿参数的大型模型。LaBSE[1]就是 Google 发布的这样一个模型,基于 BERT 模型。
LaBSE 或“语言不可知的 BERT 句子嵌入”专注于双文本挖掘、句子/嵌入相似性任务。它使用“单词块”标记化,可以为 109 种语言生成句子嵌入([CLS]标记从模型的最终层嵌入表示句子嵌入)。虽然,他们还没有报道该模型在其他下游任务如分类或命名实体识别(NER)中的性能,也没有太多用于这类下游任务。LaBSE 的架构是一个“双编码器”模型(带附加余量 Softmax 的双向双编码器),这意味着它有两个基于“BERT-base”模型编码器的编码器模块。这两个编码器分别对源句子和目标句子进行编码,并提供给一个评分函数(余弦相似度)来对它们的相似度进行排序。LaBSE 的训练损失函数就是建立在这个评分的基础上的,这个评分就是前面提到的“加性边际 Softmax”。
设置事物
(我会尽量保持简单,同时包括重要的观点)LaBSE 的官方或原始模型由作者发布到“tensor flow Hub”(https://www.tensorflow.org/hub/),我将使用它。该模块依赖于 Tensorflow (2.4.0+将是伟大的,我正在使用 2.5.0)有其他必要的库,他们可以使用 pip 安装。
注意: 到目前为止(据我所知)Conda 环境不支持 tfhub 模型+ GPU。如果您尝试使用这样的设置,它将总是(自动)退回到 Tensorflow 的 CPU 版本或抛出错误。因此,如果使用 GPU,Conda 应该不在考虑范围内。()https://github.com/tensorflow/text/issues/644
首先,需要安装一些必要的库,(我用的是 Ubuntu 机器)
!pip install tensorflow-hub!pip install tensorflow-text # Needed for loading universal-sentence-encoder-cmlm/multilingual-preprocess!pip install tf-models-official
我们可以进口它们,
import tensorflow as tfimport tensorflow_hub as hubimport tensorflow_text as text from official.nlp import optimization
显然,如果需要的话,你也应该导入其他的公共库(numpy,pandas,sklearn ),我不会在这里提到。
对于分类任务,我们可以使用预先训练的 109 种语言的任何标记数据集(或者也可以是不支持的,这没有关系!但是有一些性能下降)。我们要做的是对模型进行微调,即使用额外的数据集(与庞大的预训练数据集或语料库相比,较小的数据集)训练预训练模型,以便将模型微调到我们特定的分类(或任何其他)任务。作为起点,我们可以使用 IMDb 电影评论数据集。(https://ai.stanford.edu/~amaas/data/sentiment/)。因此,我们的任务将变成“二元情感分类”任务。数据集由 25k 训练和 25k 测试数据组成。
!wget -c [https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz](https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz) -O — | tar -xzAUTOTUNE = tf.data.AUTOTUNE
batch_size = 32 #8 #16
seed = 42raw_train_ds = tf.keras.preprocessing.text_dataset_from_directory(
‘aclImdb/train’,
batch_size=batch_size,
validation_split=0.2,
subset=’training’,
seed=seed)class_names = raw_train_ds.class_names
train_ds = raw_train_ds.cache().prefetch(buffer_size=AUTOTUNE)val_ds = tf.keras.preprocessing.text_dataset_from_directory(
‘aclImdb/train’,
batch_size=batch_size,
validation_split=0.2,
subset=’validation’,
seed=seed)val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)test_ds = tf.keras.preprocessing.text_dataset_from_directory(
‘aclImdb/test’,
batch_size=batch_size)test_ds = test_ds.cache().prefetch(buffer_size=AUTOTUNE)
我们可以使用 Tensorflow 构建的数据管道作为输入数据。(如果使用 TF 的早期版本,该功能可能无法完全或至少不能直接使用。).接下来,我们需要“预处理”这些数据,然后输入到我们将要构建的模型中。之后,预处理的数据可以被编码或嵌入向量空间。为此,我们可以定义以下变量,我们将使用 LaBSE 的版本 2(https://tfhub.dev/google/LaBSE/2,版本 1 是发布到 TFhub 的初始模型)
tfhub_handle_preprocess=”[https://tfhub.dev/google/universal-sentence-encoder-cmlm/multilingual-preprocess/2](https://tfhub.dev/google/universal-sentence-encoder-cmlm/multilingual-preprocess/2)"
tfhub_handle_encoder=”[https://tfhub.dev/google/LaBSE/2](https://tfhub.dev/google/LaBSE/2)"
建立模型
接下来,我们可以建立模型。下面,已经定义了一个函数来建立具有一些特定层的模型。
def build_classifier_model():
text_input = tf.keras.layers.Input(shape=(), dtype=tf.string, name=’text’)
preprocessing_layer = hub.KerasLayer(tfhub_handle_preprocess, name=’preprocessing’)
encoder_inputs = preprocessing_layer(text_input)
encoder = hub.KerasLayer(tfhub_handle_encoder, trainable=True, name=’LaBSE_encoder’)
outputs = encoder(encoder_inputs)
net = outputs[‘pooled_output’]
net = tf.keras.layers.Dropout(0.1)(net)
net = tf.keras.layers.Dense(1, name=’classifier’)(net)
return tf.keras.Model(text_input, net)
你可以注意到模型中有一个术语“pooled_outputs ”,它指的是本文前面提到的句子的[CLS]令牌表示。(另一种输出形式是‘sequence _ outputs’)。编码器层上的“trainable = True”参数或标志意味着,在不使用数据集进行微调的同时,我们也可以更新原始模型的权重/参数的权重。(这也被称为“全局微调”)。
encoder = hub.KerasLayer(tfhub_handle_encoder, trainable=True, name=’LaBSE_encoder’)
net = outputs[‘pooled_output’]
如果我们希望保持原始模型的权重不变,那么它将被称为“基于特征的微调”或“固定维度方法”(在文献中有不同的术语)。此外,在充当模型的分类器层的编码器(下降和密集)之后添加了一些附加层。这是在文献中经常发现的这种分类的组合。
对于优化器,Adam 或 AdamW(更多)是首选,我们可以像下面这样设置。基于数据集或任务,学习率可能会改变(在大多数情况下会降低)。Keras(https://keras.io/guides/keras_tuner/)或类似“Wandb”(https://wandb.ai/site)的服务中已经提供的超参数优化方法也可用于寻找最佳参数,如学习速率和批量大小。
from tensorflow_addons.optimizers import AdamW
step = tf.Variable(0, trainable=False)
schedule = tf.optimizers.schedules.PiecewiseConstantDecay(
[1000], [5e-5,1e-5])
lr = 1 * schedule(step)
wd = lambda: 1e-6 * schedule(step)
optimizer=AdamW(learning_rate=lr,weight_decay=wd)
接下来,可以用 mode.fit()方法对模型进行编译和训练。
classifier_model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
optimizer=optimizer,
metrics=tf.keras.metrics.BinaryAccuracy(threshold=0.0))history = classifier_model.fit(train_ds,validation_data=val_ds,
epochs=epochs, batch_size=32)
时期的数量可以设置为 3、4 或 5,这通常是足够的。我们也可以包括像“提前停止”这样的方法。对这样的大型模型使用“K-Fold 交叉验证”并不常见。相反,我们可以对输入数据选择使用不同的随机种子多次运行这个模型。从模型中构建、运行和获得结果是相当容易的。经过训练的模型可以被保存并用于预测新的数据等。如张量流模型通常所做的那样。
在我看来,与 XLM-R、或等模型相比,LaBSE 模型在文本分类等任务上可能表现不佳,因为 LaBSE 最初是为双文本挖掘或句子相似性任务而构建和训练的,为了获得更好的结果,可能需要更多的训练数据(微调数据)。LaBSE 在文献中也没有太多用于分类任务(根据我的知识和论文本身对谷歌学术的 38 次引用)。对于这里的任务,我获得了略高于 50%的准确度、精确度、召回率和 f1 分数。这也是用一些随机选择的超参数完成的,因此如果超参数也被改变/调整,结果可能会得到改善。(使用 LaBSE 版本 1(https://medium . com/swlh/language-agnostic-text-classification-with-LaBSE-51 a4 f 55 dab 77)进行了一些类似的工作,但是使用了更大的训练数据集。)
无论如何,我希望听到反馈,评论或其他人的经验。所以。请随意评论您的想法和建议。感谢阅读!!!
参考文献
[1] —语言不可知的伯特语句嵌入,冯,杨,丹尼尔 Cer,纳文阿里瓦扎甘,,arXiv:2007.01852 v1【cs .CL]
微调语言模型容易乱说
一个开源库,用几行代码训练和使用生成文本模型
赛义德·卡里米在 Unsplash 上的照片
如果您想跳过这一步,只看如何微调您自己的数据集,您可以跳过本文的其余部分,只查看 colab 笔记本!
https://github.com/bigthonk/blather
做客座演讲是我最喜欢的事情之一;没有任何责任的教学乐趣。我在讲座中的目标是让学生对机器学习感到兴奋,让他们玩实际的例子,然后走开。
本周,我有机会与亚利桑那大学网络项目的一些学生谈论机器学习。在一项关于问题的课前调查中,班上学生确定的一个主要问题是高保真机器人的威胁,这些机器人能够影响社交媒体上的对话。
创建能够影响选举或传播虚假信息的僵尸网络是一项范围广泛得多的任务,无论是从传播此类信息的道德问题还是从复杂性来看,都不是一个班级能够完成的。作为简单的第一步,我们可以从讨论如何让一个机器人用合适的内容和风格来表达帖子开始。这个子任务可以通过使用微调的自然语言模型来完成。像 GPT 家族,XLNet,或者我们芝麻街的朋友,BERT 和 ELMo 这样的语言模型,对于大多数个人来说,都是超出从头训练范围的强大模型。令人欣慰的是,开源社区已经加快步伐,开发了预先训练的模型,允许我们这些无法访问重要数据和计算的人进行实验。
不幸的是,这些模型的直接应用将提供对我们的开源朋友训练它们的训练数据集有强烈偏见的解决方案。对于我们提出的僵尸网络应用程序,这将使我们很难获得与我们试图模仿的理想人格接近的帖子。为了克服这个缺点,我们采用了一种称为微调的方法。微调模型是指采用在大型数据集上训练的模型,并在具有更好的样式和内容适用性的较小数据集上对模型进行一些部分再训练。这种方法允许我们使用模型,否则由于缺乏数据或计算资源,我们很难进行计算训练。
在这里,我遇到了一个问题,我想向学生介绍一些自然语言模型的高级概念,并给他们一些工具来训练和试验他们自己的模型,而不会让他们厌烦或以压倒性的方式暴露所有的细节。如果有一个简单的库,允许我训练模型,然后使用它们生成文本,而不必了解表面下发生的许多事情,那该多好。
这让我开发了 agough,这是一个简单的抽象库,位于奇妙的 huggingface 库之上。https://huggingface.co/
废话基本上就是这样,你的选择更少
ough 允许用户从文本文件中读取数据集,并训练模型(目前只支持 GPT-2,但我计划在未来添加对其他模型的支持),然后用户可以根据需要从模型中生成样本或保存/加载模型。
第一步。安装乱说
!pip install blather
第二步。进口废话
from blather import Blather
第三步。创建一个乱说对象
blather = Blather()
第四步。阅读一些文本
blather.read("prince.txt")
这将产生一个训练时间估计,并最终产生一些训练统计。您可以选择传递一个具有所需周期数的历元参数,因为它默认为仅训练一个历元。
Training...
Estimated Training time of 3 minutes
Running Validation...
Validation Loss: 1.62[{'Training Loss': 2.586719648164395,
'Valid. Loss': 1.6193444598011855,
'epoch': 1}]
第五步。写一些文字
blather.write("The fool was known to blather about")
这将调用模型为我们的提示文本生成一个结尾,在这种情况下,我们的马基雅维利式机器人说…
The fool was known to blather about it at every time, and I never heard a word of it," said the pope to Olivertronicus in the year 1543
摘要
我写乱说是为了给那些对微调自己的语言模型感兴趣,但又不想太深入了解这样做的细节的人提供帮助。我希望它对一些人有帮助,或者至少有娱乐性。如果你对这个项目感兴趣,或者只是想谈谈数据科学或 ML,请联系我们。
用于句子蕴含的微调预训练转换器模型
在 MultiNLI 数据集上微调 BERT 的 PyTorch 和 Hugging Face 实现
图片来自 PNGWING 。
在本文中,我将描述使用 MultiNLI 数据集(Bowman et al. 通过推理理解句子的大范围挑战语料库)对诸如 BERT 和 ALBERT 之类的预训练模型进行微调的过程。模型将使用拥抱人脸库加载,并使用 PyTorch 进行微调。
什么是蕴涵?
为了理解蕴涵,让我们从一个例子开始。
1。吉姆每天早上骑自行车去上学。
2。吉姆会骑自行车。
如果一个提出的前提是真的,就产生了蕴涵。在这个例子中,如果句子“吉姆每天早上骑自行车去上学。”是真的,那么前提是吉姆每天早上都去上学,吉姆也知道如何骑自行车。因此,这将使第二句话,或假设,也为真。
用简单的术语来定义蕴涵,如果 X 为真并且 Y 可以从其逻辑上导出,那么一个句子 Y 被称为蕴涵句子 X 。对于我使用的数据集,一对句子可以是相互依存的,可以是中性的,也可以是相互矛盾的——下一节将详细介绍数据集。
MultiNLI 数据集
多体裁自然语言推理(MultiNLI)语料库是一种设计用于开发和评估机器学习模型以理解句子的数据集。它有超过 433,000 个示例,是可用于自然语言推理(也称为识别文本蕴涵)的最大数据集之一。该数据集的设计还使得在斯坦福 NLI 语料库上训练的现有机器学习模型也可以使用 MultiNLI 进行评估。你可以在论文中了解更多关于这个数据集的信息——一个通过推理理解句子的覆盖面广的挑战语料库。
作为训练过程的一部分,数据集中考虑了 3 列—“gold _ label”、“句子 1”(前提)和“句子 2”(假设)。“gold_label”是指示给予这对句子的标签的列。有三个标签——“蕴含”、“中性”和“矛盾”
训练集有 392702 个样本,验证集还剩 10000 个样本。
训练集。图片由作者提供。
验证集。图片由作者提供。
模特——伯特
BERT(Transformers 的双向编码器表示)是 Google 基于这篇论文中介绍的编码器-解码器 transformer 模型的语言模型。它使用变形金刚的注意力机制来学习单词的上下文含义以及它们之间的关系。伯特,以及它的改型如艾伯特、罗伯塔等。在诸如问答和自然语言推理的各种自然语言处理任务上取得了最先进的结果。
与定向长短期记忆网络不同,变压器编码器一次读取整个单词序列。这使得模型可以根据一个单词的所有环境来学习它的上下文。转换器的编码器模块将令牌序列作为输入。这些首先被嵌入到向量中,并通过前馈神经网络进行反馈。这个神经网络的输出是一个向量序列,每个向量对应于一个给定索引的输入序列。
虽然我不会详细说明 BERT 的训练过程,但是你可以阅读这篇文章来获得关于它的工作以及训练它的程序的详细描述。
微调伯特
最后,进入使用拥抱脸和 PyTorch 微调预训练 BERT 模型的过程。在这个例子中,我使用了“bert-base”模型。由于计算限制和 Google Colab 上的训练时间,这是在从原始训练集中采样的 100,000 个训练样本上训练的。
第一步涉及到创建一个 DataLoader 对象来为模型提供数据。用于序列分类的 BERT 要求数据以一定的格式排列。每个句子的开始需要有一个【CLS】标记存在,句子的结束需要一个【SEP】标记。因此,对于由两个句子组成的序列,需要将其格式化为【CLS】句子 1【SEP】句子 2【SEP】。此外,每个序列都需要有与之相关联的 segment _ ids。序列中的第一句用[0]标记,第二句用[1]标记。最后,每个序列都需要一个注意力屏蔽来帮助模型确定输入序列的哪一部分不是填充的一部分。
创建 DataLoader 对象
既然已经创建了定型集和验证集的 DataLoader 对象,那么就可以加载模型及其优化器了。对于这种情况,我将使用 BertForSequenceClassification 预训练模型。这个模型提供了一个额外的参数来添加一个可选的分类头和所需数量的标签。对于这种情况,有三个类。因此,我将 num_labels 设置为 3。这增加了一个具有三个输出单元的分类头作为最终层。
加载预训练模型
既然已经加载了模型,那么是时候进入训练和验证循环了。作为训练过程的一部分,该模型被微调了 5 个时期。
培训和验证循环
定义了训练和验证循环后,我们可以在 MultiNLI 数据集上调整模型,以尝试实现预期的性能。
Epoch 1: train_loss: 0.5973 train_acc: 0.7530 | val_loss: 0.5398 val_acc: 0.7836 01:47:59.10
Epoch 2: train_loss: 0.3623 train_acc: 0.8643 | val_loss: 0.5222 val_acc: 0.8072 01:48:18.70
Epoch 3: train_loss: 0.2096 train_acc: 0.9256 | val_loss: 0.6908 val_acc: 0.7939 01:48:11.29
Epoch 4: train_loss: 0.1295 train_acc: 0.9558 | val_loss: 0.7929 val_acc: 0.7891 01:47:59.77
Epoch 5: train_loss: 0.0916 train_acc: 0.9690 | val_loss: 0.8490 val_acc: 0.7906 01:47:52.39
从上面的损失和精度值可以看出,模型似乎在学习,同时有点过度拟合。这可以通过用更多的数据而不是采样的 100,000 个样本进行训练来解决。
感谢您阅读本文!这个项目的全部代码,以及其他模型基准,可以在https://github.com/dh1105/Sentence-Entailment找到。
参考
- 通过推理理解句子的大范围挑战语料库
- 伯特:用于语言理解的深度双向转换器的预训练
- 注意力是你所需要的一切
- ALBERT:一个用于语言表达自我监督学习的 Lite BERT】
- RoBERTa:一种稳健优化的 BERT 预训练方法
- https://towards data science . com/Bert-explained-state-of-art-state-language-model-for-NLP-F8 b 21 a9 b 6270
使用 Huggingface 的训练器微调预训练的 NLP 模型
无需原生 Pytorch 或 Tensorflow 即可微调预训练 NLP 模型的简单方法
克里斯托夫·高尔在 Unsplash 上拍摄的照片
动机:在参加一个数据科学竞赛时,我正在微调一个预先训练好的模型,并意识到使用原生 PyTorch 或 Tensorflow 来微调一个模型是多么乏味。我用 Huggingface 的训练器 API 进行了实验,并对它的简单程度感到惊讶。由于网上关于如何使用 Huggingface 的训练器 API 的例子很少,我希望提供一个简单的例子,说明如何使用训练器来微调你的预训练模型。
在我们开始之前,这里有一些理解本文的先决条件:
- 对 Python 的中级理解
- 对训练神经网络模型的基本理解
- 对迁移学习的基本理解
为了节省您的时间,我将只为您提供代码,这些代码可用于使用训练器 API 来训练和预测您的模型。然而,如果你有兴趣了解它是如何工作的,请继续阅读。
步骤 1: 初始化预训练模型和记号赋予器
代码所基于的示例数据集
在上面的代码中,使用的数据是 IMDB 电影情感数据集。这些数据允许我们训练一个模型来检测电影评论的情绪- 1 是积极的,而 0 是消极的。这是序列分类的 NLP 任务,因为我们想要将每个评论(文本序列)分类为正面或负面。
有许多预训练的模型可以用来训练我们的情感分析模型,让我们以预训练的 BERT 为例。预训练的 BERT 模型有很多变体, bert-base-uncased 只是其中一种变体。你可以从拥抱面部模型页面搜索更多预训练模型。
model_name = "bert-base-uncased"
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)
由于我们使用的是预训练模型,我们需要确保输入数据的形式与预训练模型的训练形式相同。因此,我们需要使用模型的名称来实例化记号赋予器。
既然已经初始化了模型和记号化器,我们可以继续预处理数据了。
步骤 2: 使用预训练的标记器预处理文本
X_train_tokenized = tokenizer(X_train, padding=True, truncation=True, max_length=512)
X_val_tokenized = tokenizer(X_val, padding=True, truncation=True, max_length=512)
让我们使用前面初始化的标记器对文本进行预处理。
我们用于标记器的输入文本是一个字符串列表。
我们已经设置了padding=True, truncation=True, max_length=512
,这样我们可以为模型获得相同长度的输入——长文本将被截断为 512 个标记,而短文本将添加额外的标记,使其成为 512 个标记。
使用 512 个令牌,因为这是 BERT 模型可以采用的最大令牌长度。
对文本进行标记后,您将得到一个包含 3 个键的 python 字典:
- 输入标识
- 令牌类型标识
- 注意 _ 屏蔽
步骤 3: 创建 torch 数据集
训练器 API 要求模型在**torch.utils.data.Dataset**
类中。因此,我们需要创建一个从 torch Dataset 类继承的新类。
在继承的类中,我们需要有__getitem__
和__len__
方法,它们允许训练器创建批量数据并分别获得长度。
class Dataset(torch.utils.data.Dataset):
def __init__(self, encodings, labels=None):
self.encodings = encodings
self.labels = labels
def __getitem__(self, idx):
item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
if self.labels:
item["labels"] = torch.tensor(self.labels[idx])
return item def __len__(self):
return len(self.encodings["input_ids"])train_dataset = Dataset(X_train_tokenized, y_train)
val_dataset = Dataset(X_val_tokenized, y_val)
将默认 labels 参数设置为 None 的目的是,我们可以重用该类来预测看不见的数据,因为这些数据没有标签。
__getitem__
方法基本上为每个文本返回一个值字典。通过运行该方法,当在训练过程中批量处理数据时,它为每个文本创建一个带有input_ids
、attention_mask
和token_type_ids
的字典。
__len__
方法需要返回输入数据的长度。
步骤 4: 定义培训参数和培训师
def compute_metrics(p):
pred, labels = p
pred = np.argmax(pred, axis=1)
accuracy = accuracy_score(y_true=labels, y_pred=pred)
recall = recall_score(y_true=labels, y_pred=pred)
precision = precision_score(y_true=labels, y_pred=pred)
f1 = f1_score(y_true=labels, y_pred=pred) return {"accuracy": accuracy, "precision": precision, "recall": recall, "f1": f1} # Define Trainer
args = TrainingArguments(
output_dir="output",
evaluation_strategy="steps",
eval_steps=500,
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
num_train_epochs=3,
seed=0,
load_best_model_at_end=True,)
trainer = Trainer(
model=model,
args=args,
train_dataset=train_dataset,
eval_dataset=val_dataset,
compute_metrics=compute_metrics,
callbacks=[EarlyStoppingCallback(early_stopping_patience=3)],)
# Train pre-trained model
trainer.train()
这就是培训师功能的神奇之处。我们可以在 TrainingArguments 和 Trainer 类中定义训练参数,也可以用一个命令训练模型。
我们需要首先定义一个函数来计算验证集的指标。由于这是一个二元分类问题,我们可以使用准确度、精确度、召回率和 f1 分数。
接下来,我们在 TrainingArgs 和 Trainer 类中指定一些训练参数,设置预训练模型、训练数据和评估数据。
在我们定义了参数之后,只需运行trainer.train()
来训练模型。
培训师的培训示例
第五步:进行预测
# Tokenize test data
X_test_tokenized = tokenizer(X_test, padding=True, truncation=True, max_length=512) # Create torch dataset
test_dataset = Dataset(X_test_tokenized) # Load trained model
model_path = "output/checkpoint-50000"
model = BertForSequenceClassification.from_pretrained(model_path, num_labels=2) # Define test trainer
test_trainer = Trainer(model) # Make prediction
raw_pred, _, _ = test_trainer.predict(test_dataset) # Preprocess raw predictions
y_pred = np.argmax(raw_pred, axis=1)
训练完模型后,我们对测试数据重复相同的步骤:
- 使用预训练的标记器标记测试数据
- 创建 torch 数据集
- 负载训练模型
- 定义培训师
要从前面的步骤中加载已训练模型,请将 model_path 设置为包含已训练模型权重的路径。
为了进行预测,也只需要一个命令test_trainer.predict(test_dataset)
。
做了一个预测之后,你只会得到原始的预测。将它转换成可用的格式需要额外的预处理步骤。
因为这个任务只是一个简单的序列分类任务,所以我们可以只获得轴 1 上的 argmax。请注意,其他 NLP 任务可能需要不同的方式来预处理原始预测。
我希望这篇文章将有助于简化你微调预训练 NLP 模型的过程。请随意阅读官方的 Huggingface 文档,以更好地理解代码并了解它还能做什么。
Edit 1 (23/6/21): Removed save_steps
parameter from TrainingArgument
as it is ignored when load_best_model_at_end
is set to True. Thanks 杨程 for the feedback!
参考
[1]https://huggingface.co/transformers/training.html
[2]https://hugging face . co/transformers/main _ classes/trainer . html
文本摘要 BART 大模型的优化
微调模型以总结世界新闻
来源:https://unsplash.com/photos/Mwuod2cm8g4
据《大西洋月刊》T4 报道,纽约时报每天发表 150 多篇文章,周日发表 250 多篇。《华尔街日报》每天刊登大约 240 篇报道。其他网站,如 Buzzfeed,每月发布 6000 多篇报道。
随着信息量的增加,摘要成为机器学习/自然语言处理(NLP)中一项非常受欢迎的任务也就不足为奇了。
总结有两种主要方法。第一种,抽取摘要,旨在识别最重要的句子,并使用那些精确的句子作为摘要。
更高级的方法是抽象概括。它包括以一种新的方式解释和总结信息。这是我们将在本文中使用的方法。
BART 大型模型
像任何 NLP 任务一样,存在可以用作起点的高级模型。这里的想法是使用预训练神经网络模型的所有权重,并将其用作初始点,以便加速训练并提高性能。
在本教程中,使用的模型被称为facebook/bart-large-cnn
,由脸书开发。它包含 1024 个隐藏层和 406 个参数,并使用 CNN(一个新闻摘要数据集)进行了微调。
如你所见,这个模型非常庞大,所以我建议你使用 Google Colab 来运行代码。它是 100%免费的,并提供轻松访问 GPU,这将加快训练速度。
代码
1.导入和准备数据
让我们从导入数据(并稍微清理一下)以及微调模型所需的库开始。
我将使用可以在这里找到的数据。我将只使用数据集的一小部分来总结被归类为阴谋的新闻。
这里没什么特别的。blurr 库将 huggingface transformer 模型(就像我们使用的那个)与 fast.ai 集成在一起,fast . ai 是一个旨在使深度学习比以往任何时候都更容易使用的库。
正如您在第 22 行看到的,我在本教程中只使用了数据的一个子集,主要是因为内存和时间的限制。这是数据的样子。
这里,text
列将被用作我们想要总结的文本,而title
列将被用作我们想要获得的目标。
我这样做是因为我没有实际的总结,但如果你有,当然你应该把它作为目标。
2.导入模型
在本节中,我们将导入预先训练的模型,并为训练准备数据。
这里有点复杂,所以让我们一行一行地看一下每件事是怎么做的:
- 第 2–3 行:这是我们导入预训练 BART 大型模型的地方,我们将对其进行微调。
- 第 7–15 行:这是处理创建小批量输入和目标的地方。我们还指定了任务是什么,以及一组超参数(在 text_gen_kwargs 字典中)。
- 第 20 行:这一行包含创建数据集所需的内容。我们在这里提供什么是文本,什么是目标摘要。
- 第 21 行:我们创建数据集并提供 batch_size。我建议保持这个数字很小,否则你可能会遇到
CUDA OUT OF MEMORY
错误。
要了解更多关于不同功能和参数的信息,我邀请您查看文档这里和这里。
3.培养
我们现在可以开始实际训练了。
- 第 2–9 行:创建一个字典,其中包含一系列性能指标,这些指标将用于在训练期间评估模型。
- 第 17–19 行:学习函数是我们指定数据、模型和损失函数的地方,这些将用于训练。
- 第 26 行:使用 1cycle 策略来拟合一个模型,这是在这篇论文中介绍的,旨在使用较大的学习率非常快速地训练神经网络。我们在这一行中指定了历元数(3)和学习率。
4.生成预测
现在让我们看看如何给定一个文本生成摘要。
我只返回一个概要,但是你可以返回多个概要,并从给定的选项中选择最佳的概要。
作为一个例子,这里有一个文本和返回的摘要。
这就对了。考虑到我所做的训练是如此之少,仅仅使用了一个非常小的数据集,这是非常令人印象深刻的。当你想对一个给定的主题保持更新,而不需要阅读关于它的所有内容时,你肯定可以看到摘要的用途。
现在,您已经知道如何微调文本摘要的 BART large。非常感谢你的阅读,我希望我能有所帮助!
代码可以在这里找到。
成为会员:https://francoisstamant.medium.com/membership
用于发票识别的微调变压器模型
从注释到训练的逐步指南
安德烈·波波夫摄于 Dreamstime
介绍
基于我最近关于如何为 NLP 应用注释 pdf 和扫描图像的教程,我们将尝试在一个包含法语和英语发票的注释定制数据集上微调最近发布的微软布局 LM 模型。虽然之前的教程侧重于使用公开可用的 FUNSD 数据集来微调模型,但这里我们将展示从注释和预处理到训练和推理的整个过程。
LayoutLM 模型
LayoutLM 模型基于 BERT 架构,但增加了两种类型的输入嵌入。第一种是 2d 位置嵌入,表示文档内标记的相对位置,第二种是文档内扫描标记图像的图像嵌入。该模型在几个下游任务中取得了新的最先进的结果,包括表单理解(从 70.72 到 79.27)、收据理解(从 94.02 到 95.24)和文档图像分类(从 93.07 到 94.42)。有关更多信息,请参考原文。
幸运的是,这个模型是开源的,可以在 huggingface 库中获得。谢谢微软!
对于本教程,我们将直接从 huggingface 库中克隆模型,并在我们自己的数据集上对其进行微调,下面是 google colab 的链接。但是首先,我们需要创建训练数据。
https://colab . research . Google . com/drive/1 nkvuyw 6 ne 25 hoz _ IApiv _ miyb 4 LX caq?usp =共享
发票注释
使用 UBIAI 文本注释工具,我已经注释了大约 50 张个人发票。我对提取实体的键和值感兴趣;例如,在下面的文本“日期:06/12/2021”中,我们会将“日期”注释为 DATE_ID,将“06/12/2021”注释为 Date。提取键和值将有助于我们将数值与它们的属性相关联。以下是所有已被注释的实体:
DATE_ID, DATE, INVOICE_ID, INVOICE_NUMBER,SELLER_ID, SELLER, MONTANT_HT_ID, MONTANT_HT, TVA_ID, TVA, TTC_ID, TTC
以下是一些实体定义:
MONTANT_HT: Total price pre-taxTTC: Total price with taxTVA: Tax amount
以下是使用 UBIAI 的注释发票示例:
作者图片:带注释的发票
标注后,我们直接从 UBIAI 中以正确的格式导出训练和测试文件,没有任何预处理步骤。导出将包括每个训练和测试数据集的三个文件,以及一个包含所有名为 labels.txt 的标签的文本文件:
培训/测试. txt
2018 O
Sous-total O
en O
EUR O
3,20 O
€ O
TVA S-TVA_ID
(0%) O
0,00 € S-TVA
Total B-TTC_ID
en I-TTC_ID
EUR E-TTC_ID
3,20 S-TTC
€ O
Services O
soumis O
au O
mécanisme O
d'autoliquidation O
- O
Train/Test_box.txt(包含每个令牌的边界框):
€ 912 457 920 466
Services 80 486 133 495
soumis 136 487 182 495
au 185 488 200 495
mécanisme 204 486 276 495
d'autoliquidation 279 486 381 497
- 383 490 388 492
Train/Test_image.txt(包含边界框、文档大小和名称):
€ 912 425 920 434 1653 2339 image1.jpg
TVA 500 441 526 449 1653 2339 image1.jpg
(0%) 529 441 557 451 1653 2339 image1.jpg
0,00 € 882 441 920 451 1653 2339 image1.jpg
Total 500 457 531 466 1653 2339 image1.jpg
en 534 459 549 466 1653 2339 image1.jpg
EUR 553 457 578 466 1653 2339 image1.jpg
3,20 882 457 911 467 1653 2339 image1.jpg
€ 912 457 920 466 1653 2339 image1.jpg
Services 80 486 133 495 1653 2339 image1.jpg
soumis 136 487 182 495 1653 2339 image1.jpg
au 185 488 200 495 1653 2339 image1.jpg
mécanisme 204 486 276 495 1653 2339 image1.jpg
d'autoliquidation 279 486 381 497 1653 2339 image1.jpg
- 383 490 388 492 1653 2339 image1.jpg
标签. txt:
B-DATE_ID
B-INVOICE_ID
B-INVOICE_NUMBER
B-MONTANT_HT
B-MONTANT_HT_ID
B-SELLER
B-TTC
B-DATE
B-TTC_ID
B-TVA
B-TVA_ID
E-DATE_ID
E-DATE
E-INVOICE_ID
E-INVOICE_NUMBER
E-MONTANT_HT
E-MONTANT_HT_ID
E-SELLER
E-TTC
E-TTC_ID
E-TVA
E-TVA_ID
I-DATE_ID
I-DATE
I-SELLER
I-INVOICE_ID
I-MONTANT_HT_ID
I-TTC
I-TTC_ID
I-TVA_ID
O
S-DATE_ID
S-DATE
S-INVOICE_ID
S-INVOICE_NUMBER
S-MONTANT_HT_ID
S-MONTANT_HT
S-SELLER
S-TTC
S-TTC_ID
S-TVA
S-TVA_ID
微调 LayoutLM 模型:
在这里,我们使用带有 GPU 的 google colab 来微调模型。以下代码基于原创 layoutLM 论文和本教程。
首先,安装 layoutLM 包…
! rm -r unilm! git clone -b remove_torch_save https://github.com/NielsRogge/unilm.git! cd unilm/layoutlm! pip install unilm/layoutlm
…以及将从其中下载模型的 transformer 包:
! rm -r transformers! git clone https://github.com/huggingface/transformers.git! cd transformers! pip install ./transformers
接下来,创建一个包含 labels.txt 中唯一标签的列表:
from torch.nn import CrossEntropyLossdef get_labels(path):
with open(path, "r") as f:
labels = f.read().splitlines()
if "O" not in labels:
labels = ["O"] + labels
return labelslabels = get_labels("./labels.txt")
num_labels = len(labels)
label_map = {i: label for i, label in enumerate(labels)}
pad_token_label_id = CrossEntropyLoss().ignore_index
然后,创建 pytorch 数据集和数据加载器:
from transformers import LayoutLMTokenizer
from layoutlm.data.funsd import FunsdDataset, InputFeatures
from torch.utils.data import DataLoader, RandomSampler, SequentialSamplerargs = {'local_rank': -1,
'overwrite_cache': True,
'data_dir': '/content/data',
'model_name_or_path':'microsoft/layoutlm-base-uncased',
'max_seq_length': 512,
'model_type': 'layoutlm',}# class to turn the keys of a dict into attributes
class AttrDict(dict):
def __init__(self, *args, **kwargs):
super(AttrDict, self).__init__(*args, **kwargs)
self.__dict__ = selfargs = AttrDict(args)tokenizer = LayoutLMTokenizer.from_pretrained("microsoft/layoutlm-base-uncased")# the LayoutLM authors already defined a specific FunsdDataset, so we are going to use this here
train_dataset = FunsdDataset(args, tokenizer, labels, pad_token_label_id, mode="train")
train_sampler = RandomSampler(train_dataset)
train_dataloader = DataLoader(train_dataset,
sampler=train_sampler,
batch_size=2)eval_dataset = FunsdDataset(args, tokenizer, labels, pad_token_label_id, mode="test")
eval_sampler = SequentialSampler(eval_dataset)
eval_dataloader = DataLoader(eval_dataset,
sampler=eval_sampler,
batch_size=2)batch = next(iter(train_dataloader))input_ids = batch[0][0]tokenizer.decode(input_ids)
从 huggingface 加载模型。这将在数据集上进行微调。
from transformers import LayoutLMForTokenClassification
import torchdevice = torch.device("cuda" if torch.cuda.is_available() else "cpu")model = LayoutLMForTokenClassification.from_pretrained("microsoft/layoutlm-base-uncased", num_labels=num_labels)
model.to(device)
最后,开始训练:
from transformers import AdamW
from tqdm import tqdmoptimizer = AdamW(model.parameters(), lr=5e-5)global_step = 0
num_train_epochs = 50
t_total = len(train_dataloader) * num_train_epochs # total number of training steps#put the model in training mode
model.train()
for epoch in range(num_train_epochs):
for batch in tqdm(train_dataloader, desc="Training"):
input_ids = batch[0].to(device)
bbox = batch[4].to(device)
attention_mask = batch[1].to(device)
token_type_ids = batch[2].to(device)
labels = batch[3].to(device)# forward pass
outputs = model(input_ids=input_ids, bbox=bbox, attention_mask=attention_mask, token_type_ids=token_type_ids,
labels=labels)
loss = outputs.loss# print loss every 100 steps
if global_step % 100 == 0:
print(f"Loss after {global_step} steps: {loss.item()}")# backward pass to get the gradients
loss.backward()#print("Gradients on classification head:")
#print(model.classifier.weight.grad[6,:].sum())# update
optimizer.step()
optimizer.zero_grad()
global_step += 1
你应该可以看到训练进度和损失得到更新。
图片作者:布局 LM 训练进行中
训练后,使用以下函数评估模型性能:
import numpy as np
from seqeval.metrics import (
classification_report,
f1_score,
precision_score,
recall_score,
)eval_loss = 0.0
nb_eval_steps = 0
preds = None
out_label_ids = None# put model in evaluation mode
model.eval()
for batch in tqdm(eval_dataloader, desc="Evaluating"):
with torch.no_grad():
input_ids = batch[0].to(device)
bbox = batch[4].to(device)
attention_mask = batch[1].to(device)
token_type_ids = batch[2].to(device)
labels = batch[3].to(device)# forward pass
outputs = model(input_ids=input_ids, bbox=bbox, attention_mask=attention_mask, token_type_ids=token_type_ids,
labels=labels)
# get the loss and logits
tmp_eval_loss = outputs.loss
logits = outputs.logitseval_loss += tmp_eval_loss.item()
nb_eval_steps += 1# compute the predictions
if preds is None:
preds = logits.detach().cpu().numpy()
out_label_ids = labels.detach().cpu().numpy()
else:
preds = np.append(preds, logits.detach().cpu().numpy(), axis=0)
out_label_ids = np.append(
out_label_ids, labels.detach().cpu().numpy(), axis=0
)# compute average evaluation loss
eval_loss = eval_loss / nb_eval_steps
preds = np.argmax(preds, axis=2)out_label_list = [[] for _ in range(out_label_ids.shape[0])]
preds_list = [[] for _ in range(out_label_ids.shape[0])]for i in range(out_label_ids.shape[0]):
for j in range(out_label_ids.shape[1]):
if out_label_ids[i, j] != pad_token_label_id:
out_label_list[i].append(label_map[out_label_ids[i][j]])
preds_list[i].append(label_map[preds[i][j]])results = {
"loss": eval_loss,
"precision": precision_score(out_label_list, preds_list),
"recall": recall_score(out_label_list, preds_list),
"f1": f1_score(out_label_list, preds_list),
}
只有 50 个文档,我们得到以下分数:
作者图片:培训后的评估分数
注释多了,肯定能得更高的分数。
最后,保存模型以供将来预测:
PATH='./drive/MyDrive/trained_layoutlm/layoutlm_UBIAI.pt'torch.save(model.state_dict(), PATH)
推论:
现在有趣的部分来了,让我们上传一张发票,对其进行 OCR,并提取相关实体。对于此测试,我们使用的发票不在培训或测试数据集中。为了解析发票中的文本,我们使用开源的 Tesseract 包。让我们安装软件包:
!sudo apt install tesseract-ocr!pip install pytesseract
在运行预测之前,我们需要解析图像中的文本,并将标记和边界框预处理为特征。为此,我创建了一个预处理 python 文件 layoutLM_preprocess.py ,这将使预处理图像更加容易:
import sys
sys.path.insert(1, './drive/MyDrive/UBIAI_layoutlm')
from layoutlm_preprocess import *image_path='./content/invoice_test.jpg'image, words, boxes, actual_boxes = preprocess(image_path)
接下来,加载模型并获得单词预测及其边界框:
model_path='./drive/MyDrive/trained_layoutlm/layoutlm_UBIAI.pt'model=model_load(model_path,num_labels)word_level_predictions, final_boxes=convert_to_features(image, words, boxes, actual_boxes, model)
最后,显示带有预测实体和边界框的图像:
draw = ImageDraw.Draw(image)font = ImageFont.load_default()def iob_to_label(label):
if label != 'O':
return label[2:]
else:
return ""label2color = {'data_id':'green','date':'green','invoice_id':'blue','invoice_number':'blue','montant_ht_id':'black','montant_ht':'black','seller_id':'red','seller':'red', 'ttc_id':'grey','ttc':'grey','':'violet', 'tva_id':'orange','tva':'orange'}for prediction, box in zip(word_level_predictions, final_boxes):
predicted_label = iob_to_label(label_map[prediction]).lower()
draw.rectangle(box, outline=label2color[predicted_label]) draw.text((box[0] + 10, box[1] - 10), text=predicted_label, fill=label2color[predicted_label], font=font)image
瞧吧:
作者图片:测试发票上的预测
虽然该模型犯了一些错误,如将 TTC 标签分配给购买的商品或不识别某些 id,但它能够正确地提取卖家、发票号码、日期和 TTC。鉴于带注释的文档数量很少(只有 50 个),结果令人印象深刻,非常有希望!有了更多带注释的发票,我们将能够达到更高的 F 分数和更准确的预测。
结论:
总的来说,LayoutLM 模型的结果非常有希望,证明了 transformers 在分析半结构化文本中的有用性。该模型可以在任何其他半结构化文档上进行微调,如驾照、合同、政府文档、财务文档等。
如果您有任何问题,请不要犹豫,在下面提问或发送电子邮件至 admin@ubiai.tools。
如果你喜欢这篇文章,请喜欢并分享!
在 Twitter 上关注我们 @UBIAI5 或订阅这里!
咖啡粉中的微粒:寻找源头
咖啡数据科学
一个更好地了解烤豆子内部的机会
磨咖啡的时候,总是要在细粉和巨砾之间取得平衡。他们是不可避免的,即使是高端磨床。这是为什么呢?典型的解释是,由于咖啡易碎的特性,会产生细小的颗粒,而巨砾是最大的颗粒,仍然可以通过研磨机而不会被压碎。
有一种理论认为,豆子的内部比其余部分更脆。因此,细粒首先由内部产生,而巨砾来自豆的外部。如果这个理论不成立,那么罚款应该同样来自外壳和内部。
我决定设计一个简单快速的实验来测试这个理论。如果这是真的,这可以很好地解释为什么断续镜头比常规镜头给人不同的味道。它们是相同的场地,只是按层重新排序。然而,如果细粒层中的颗粒主要由豆子内部控制,而粗粒层中的颗粒主要由外壳控制,那么我可以看出提取过程会有什么不同。
所有图片由作者提供
硬度检查
我试着用 D 型硬度计测量豆子的内部,我注意到工具会陷入柔软的部分,通常在工具测量到超过 5 之前,豆子就会破裂。然而,如果我测量豆子的外部,我通常会得到 15 到 20 之间的读数。通常,有一个小压痕或豆裂纹,这意味着不同的硬度计类型将更好地测量硬度。
硬度测量
实验设计
为了验证这一理论,我想如果我能把粉末和砾石分开,我就能把砾石磨得更细。然后我可以比较两张照片。
我把我的小生境研磨机设置为 50,这应该会给我一个粗略的分布与一些罚款。我用我的基于图像的技术来确定粒子的体积分布,并且有一些误差,因为我发现一些筛选,但它给出了一个好主意。这里有两个凸起,一个在 300 微米左右,一个在 1100 微米左右,分别代表细粒和巨砾。
我用 800 微米和 500 微米的筛子过滤咖啡。我并不关心 500 微米的屏幕,只是综合了一下结果。我结束了> 800 微米和<800um grinds.
Above 800um, between 500um and 800um, and less than 500um
I put these two separate piles of grounds of these through the Niche on Setting 13, which is my current starting point for dialing in a shot.
Left: >800 微米,对不对:> 800 微米重新接地在设置 13
此外,我在场景 13 中研磨了一些相同的咖啡豆作为整粒咖啡豆。
然后我收集了一些粒子分布信息。我应该注意到,在研磨<800um coffee, it went through very quickly, and the distributions showed more fines were created, but it didn’t change too much.
Comparing the regrind with the Setting 13 (S13) only, they seem to follow relatively similar distributions. S13 has more fines.
Shot Performance Metrics
I used two metrics for evaluating the differences between shots: 时最后的分数和咖啡萃取。
最终得分是 7 个指标(强烈、浓郁、糖浆、甜味、酸味、苦味和余味)记分卡的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难,会影响最终得分。
使用折射仪测量总溶解固体(TDS ),该数字用于确定提取到杯中的咖啡的百分比,并结合一杯咖啡的输出重量和咖啡的输入重量,称为提取率(EY)。
数据分析
我看了几张照片。一个标准镜头在场景 13,一个在场景 13 使用大于 800 微米的粒子,一个使用 800 微米的粒子<800um on Setting 13. The shots definitely ran faster, but all three extracted similarly. I kept the Pre-infusion time the same because that variable is most tightly correlated to extraction.
Taste is where there was a very noticeable difference. The <800um particles had a much better taste, but something seemed missing. However, for the >,它不甜,有点苦。这是我在开发断奏镜头时的类似经历。
我们需要更多的数据!
我决定我需要用筛子收集更多的数据,看看豆子较软的部分和外面产生了多少细小颗粒。如果内部更容易产生细屑,那么不管研磨设置如何,都会发生这种情况。
我从设置 50 开始研磨,我用 Kruve 筛筛出大于 800 微米的颗粒。我在设置 30 时重新研磨了> 800 微米的地面。然后我把一些豆子放在 30 度的环境下磨碎来做比较。
然后我比较了这些分布,假设这种情况下的微粒低于 400 微米。如果豆子中的任何地方都有相同的导致细粒的概率,那么 800um S30 应该与 S30 具有相同的< 400um 的百分比,但几乎是一半。其中一些可能是由于以前被研磨过,但是对于更多更大的颗粒,分布肯定是不同的
我也用我的成像技术拍摄图像来观察颗粒分布。
从这些< 400um 的数据中,不太清楚差异在哪里。成像技术与筛选技术不一致,但它更精细。
让我们只关注一下<400um, throw out all other data, and add a few more data points on the lower end of the particle diameter:
There is definitely a bigger spike for 800um reground near 100um, but the more interesting piece for me is less than 60um where 800um reground is almost zero. If the fines come from the softer bits inside the bean, and those were removed during the Setting 50 grind, then it would make sense to see such a drop off.
I don’t think these results are definitive, but they point strongly at the theory that fines are the softer parts of the coffee. This really helps explain why coffee sifted to different levels tastes different, and this taste difference is the underlying reason why a staccato shot tastes better than a regular shot.
I also suspect that trying to eliminate the fines from coffee, whatever the brewing technique, is eliminating a flavor or multiple flavors not found in the rest of the bean.
If you like, follow me on Twitter 和 YouTube ,我在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以关注我中。
我的进一步阅读:
咖啡中的粉末会迁移,但不会太远:第 1 部分
咖啡数据科学
他们对拍摄的影响仍然值得怀疑
我之前在一个用过的冰球上做了一些分析,取一个横截面,观察颗粒分布的差异。与顶部相比,圆盘底部的较细颗粒尺寸略有增加。这似乎是微粒迁移的证据,尽管数量很少。
所以我决定再次进行这个实验,但是收集更多的样本来帮助提高这个结论的可信度。所以我拿了三片,分成上、中、下三块。
所有图片由作者提供
我让这些磨粒完全干燥,然后从每个磨粒中取三个样本来计算颗粒分布。对于顶部、中部和底部,我最终每个都有 9 个样本。
然后我做了一些粒子分析。
我查看了这 9 个样本的最小值、平均值和最大值。小颗粒的数量很难区分,特别是因为在最小值、平均值和最大值之间没有明确的模式。
我们可以从不同的角度来看待中位数,它可能比平均值更好。在这里,我们看到一个小图案,底部比顶部或中部有更多的小颗粒,总共约 3%或 4%。对于大约 100 微米或更小的颗粒,总差值为这些颗粒的 10%。
当我们观察图像中的表面区域时,这个故事发生了进一步的变化。我有估计数量的指标,它们显示了类似的模式。成像的问题是第三维很难捕捉。这种观点,还是有 0.6%的理由差异。
我们可以单独或累积地观察这些差异:
这两项研究都表明,粉末迁移量很小,总共不到所有粉末的 1%。
刮擦顶部和底部
我通过刮擦冰球的顶部和底部做了另一个测试。我认为这些应该是所有粒子迁移中最不同的。
这些分布显示出很小的差异。这并不是说没有区别,但这很难衡量。这也可能是一个线索,让我们知道迁徙有多好,但我现在还不确定。
科学由实验和观察组成。我得出了我最初的观察结果,即微粒不会迁移,因为我无法解决正在发生的少量移动。现在有了更好的解决细粒的能力,细粒被观察到迁移,但是只占所有粉末的一小部分。现在更大的问题是,这种细微的变化是否足以让一杯酒的味道变得不同。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中和订阅。
我的进一步阅读:
咖啡中的粉末会迁移,但不会太远:第 2 部分
咖啡数据科学
一个废断奏镜头的横截面切片
作为我深入研究细小微粒迁移的一部分,我决定用废咖啡做一些实验。在这个实验中,我使用了一个扭曲的分层镜头,通过在底部放置较粗的粉末来给细颗粒最好的迁移机会。
镜头准备
我在底部放了一个纸过滤器,目的是捕捉任何可能通过的粉末。
所有图片由作者提供
然后,在把它放进篮子之前,我对筛过的粉末进行了一些测量:
我把这个镜头换成了一个断续的镜头:
- 纸质过滤器
- 底层大于 400 微米
- 中间层是<400um
- Top Layer is <200um
- Metal mesh screen on top
While these layers are mostly separated, the separation wasn’t absolute because coffee grounds stick together. So it is very difficult to get perfectly sifted coffee.
Top is loose grounds, Bottom is tamped. Left is >圆盘底部的 400 μm,然后是中间的< 400 μm,右边是圆盘顶部的< 200um。
扣动扳机
我拔枪,结果是 1%的提取率,比预期的要高。水也浑浊,我就存了。
圆盘是干净的,过滤器的底部也相对干净。这一枪打得很均匀。
切冰球
当我试图把冰球取出来时,麻烦就开始了。因为底层是粗糙的,它没有密封的方式,我可以很容易地捣实它。较粗的颗粒没有很好地粘在一起。最后,我加了一些水,以确保它不会太干,所以它不会分裂。然后我用刀子切开一个洞把它挤出来。
很乱,但我能得到一片干净的。主要的问题是,带有较粗颗粒的圆盘底部移动了很多,一些较细的颗粒落到了圆盘的底部。
在杯子里,当我倒出液体时,剩下了一些粉末。它们可能来自冰球的底部,因为筛选并不完美。如果他们来自更高的地方,我怀疑会有更多。我也不认为他们占了场地的很大一部分。
拍摄后分析
我把冰球切成了 6 层,然后让它们干燥几天。我把每一层都和它应该有的样子进行了比较。
较粗的地面有两层奇怪的混合,其中一层有所有的细颗粒。这可能是因为我想把冰球拿出来。
我也看了累积图,大多数分布保持不变。右图是左图的放大版。
左:399um 最大 bin。右:213um 最大 bin。
平均图层
如此庞大的数据量令人应接不暇。所以我把各层平均了一下。一旦我看到分布是如何重叠的,这种比较就很有意义。
实线表示拍摄前的图层,虚线表示拍摄后的图层。
我发现奇怪的是,底层的细颗粒减少(> 400 微米),这表明大部分粗颗粒中的细颗粒会迁移到杯中。
令我惊讶的是,更多的微粒没有停留在底部的粗糙层(> 400 微米)。我也很沮丧,因为我费了很大的劲才把冰球取出来。总的来说,我认为这个实验是不确定的,它肯定没有导致更细的颗粒大量转移到底层。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中和订阅。
我的进一步阅读:
咖啡中的粉末会迁移,但不会太远:第 3 部分
咖啡数据科学
废咖啡实验
更难观察的一个变量是颗粒如何从原始研磨分布转移到提取后,因为提取改变了相关颗粒的尺寸。为了解决这个问题,我用了一个装有刚喝完的咖啡(充分混合)的圆盘,这样我就可以在拍摄前后进行测量。这个实验仍然缺乏可溶物如何影响流动以及二氧化碳的缺乏,但它代表了改变颗粒分布的最佳情况。
这是之前检验微粒迁移的实验的延续。
冰球
在我投篮后,我必须把冰球弹出来,准备削球。
弄湿冰球后,我可以把它切成底部、中间和顶部。
测量颗粒分布
我测量了拍摄前的粒子分布,然后是三层的粒子分布。对于每一层,我取了三个样本,然后对第一个图的样本取平均值。
拍摄后有一个大的转变,拍摄本身仍然有 0.9%的提取率。所以还是有一些可解的。这是 200 微米及以下的累积分布和放大版本。
我们可以只关注顶部和底部,这显示了底部样本相对于顶部样本的较大偏移。
查看这些样本的另一种方法是累积条形图。它显示底部发生了移动,但移动的幅度没有我之前在这个主题上的实验那么大。
为了更好地理解这种影响,我们可以考虑顶部和底部之间的差异。这是一个相对较小的百分比,我怀疑它代表了一杯咖啡中迁移粒子的上限。似乎 200 微米左右的累积差异是所有咖啡的 1%左右。
这个实验有助于分离可溶物、二氧化碳气体和咖啡渣的分布。它支持这样的理论,即较细的颗粒确实会迁移,但是迁移的总量大约是圆盘中总研磨物的 1%。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 LinkedIn 上找到我。也可以关注我中和订阅。
我的进一步阅读:
急救开放资料包[第 1 卷]
关于交通事故你需要知道的
作者图片
你有没有想过穿过你旁边的街道有多危险?你曾经尝试过制作评估道路安全的地图吗?或者简单地说,你是一个(地理)数据极客,想学习一些新的东西吗?如果你至少有一次回答“是”,那么这篇文章就是给你的!
在《急救开放资料包》的第一集,我将向大家展示:
- 德国巨大的事故数据库可以免费下载
- 你能从这个数据集中提取什么信息
- 为什么这样的数据集是重要的,而不是没有一个原因叫做——令人敬畏的开放数据[2]。
事故数据的内容
德国警方负责收集必要的信息到数据集[4]
在事故数据集(蒙古包)内。对德国来说,你会发现国家层面的交通事故。自 2016 年以来,警方一直在收集这些数据,并将每年进行更新。
你可能认为只有一个事故发生的地点,这就是故事的结尾。好吧,你可能没有错,但还有更多!
你不仅可以检索过去几年中发生的每起事故的 X,Y 地理坐标,还可以检索每个事件的丰富语义。属性列表包含关于一周中的小时和天的信息(原文如此!)、月份、年份、地区、事故类别、事故类型、照明和路况、车辆类型等等1。
给你一个要点,它对你意味着什么:你可能会在地图上找到一个点,描述柏林米特的一个事故地点。然后,通过一键点击,您提取出以下信息:事情发生在 2018 年 1 月 1 日上午 9 点,这一天相当黑,涉及 2 名行人、1 辆汽车和 1 辆自行车,有 3 人受轻伤,道路湿滑,事故是由于转向操作而发生的。印象深刻?我是!
柏林亚历山大广场的一次事故和可用的统计样本(在右下角)【5】
事故数据的格式
存储库作为 csv 和 shapefiles 共享(万岁。嘘!)并且每个子集覆盖一年。负责发布的单位是联邦统计局(T2)。statistisches Bundesamt(Destatis),辅助所谓的事故图集对数据集的探索。如果你打开这个链接,你会默认看到道路分类和事故数量。当然,您可以更改它,探索 Office 已经提供的更多特征和分析。事实上,你甚至可以很容易地将地图集整合到你的网站中。如果你熟悉 OGC 标准,你会很高兴看到他们也提供了 WMS 服务(是的!).
事故数据的挑战
但是,我不得不承认这个数据集有一个缺点。如果你回到项目开始的时候,到 2016 年,你会发现差不多只有一半的德国人参加了开放事故数据库项目。虽然每年都有下一个州加入该项目,但截至 2019 年,几乎所有德国州都向国家数据库报告了他们的事故。只有一个突出的州——梅克伦堡-前波莫瑞州。希望该州将很快加入其他州的行列。正如他们所说——黎明前总是最黑暗的!
事故图集的概述和数据集的覆盖范围。基于[5]
事故数据的应用
除了“内部”(从技术上来说,所有政府单位都是为你——公民——制造的😏)用于上述办公室的目的(见下图)数据的开放使其可用于各种应用。
该办公室制作的信息图之一,直观呈现了德国 2019 年死亡事故的数量。 美国联邦统计局【7】
首先,这些统计数据被用来控制交通事故的数量,从而减少道路上的死亡人数。通过公开数据,办公室鼓励每个人解决这个问题(你也是!或者 U2,如果你喜欢爱尔兰拼法的话。即使没有什么知识,人们也可以创建有洞察力的信息图表来可视化一些模式并提高公民的意识。谁知道也许你的邻居下次骑自行车会戴头盔呢?
显然,政府部门也希望将事故数量减少到几乎为零。是的,的确如此——你听说过零视力项目吗?如果没有像这个工具包这样的数据集,就不可能完全理解这个问题并选择适当的措施来解决它。
最近,世界各地的城市和国家转向绿色城市,并鼓励人们使用自行车而不是汽车。然而,许多人只是害怕使用自行车,因为事故发生率很高。城市通过广告鼓励人们,提倡健康的生活方式,但也通过定位潜在的危险区域。这些数据有助于管理者对危险街道进行现代化改造。这最终会减少事故的数量。像下面这样的创新交通解决方案应该给你一个能做什么的要点。
这样的数据集也有助于研究。让我们说,你想设计一个自动驾驶汽车掉头的算法。看似简单?但现在,尝试实施提高警惕区域的意识。考虑“不可预测”,考虑过马路的行人,而不是其他道路使用者的常规动作,在不同的天气条件下测试它,等等。我想你已经知道什么数据集可以帮助应对这一挑战。
以我个人的经验,可以说数据库确实是牛逼的开放数据。事故数据成为我的项目【T2 拯救骑自行车的人】的支柱!。我制作了网络地图应用,它允许我们分析柏林最危险的地区,探索需要道路现代化或维护的地区,并允许我们实时检查救护车是否在 15 分钟的行驶范围内。你可以查看教程来复制地图
我的网络地图应用。创建一个新的并分享它以提高社区的意识![6]
事故数据汇总
好吧,你已经知道如何利用事故数据了吗?你会如何贡献?你有没有可能受到我的地图的启发?让我知道你对这个数据集的想法,并分享你自己对如何利用这个关键(拯救生命!)数据集!
如果您想了解更多事故数据,请点击此处。
请继续关注急救开放数据工具包的下一集,了解更多关于令人敬畏的开放数据世界的信息!
参考书目
[1]Statistisches Bundesamt(Destatis)【2020】datensazbechreibung un fallatlas | Kartenanwendung der Statistischen des Bundes and der lander。已访问 17 . 01 . 2021https://un fallatlas . statistikportal . de/app/un falldatendownload/DSB _ un fallatlas . pdf
[2]科特雷尔 D. &库迪尼奇(2020) GitHub,Awesome 公开数据https://github.com/DigitalCommonsLab/awesome-opendata
[3]2019 年按选定的道路使用类型和地点分列的道路交通事故死亡人数(2020 年,T21)。访问 17 . 01 . 2021https://www . destatis . de/EN/Themes/Society-Environment/Traffic-Accidents/_ node . html # sprg 454512
[4] Loeb R. (2009) Pixabay,消防警察事故。已访问 17 . 01 . 2021https://pix abay . com/photos/fire-police-accident-police-car-1857993/
[5]德国联邦和州统计局(2020 年)。2021 年 1 月 17 日访问 https://unfallatlas.statistikportal.de/
[6]Wysocki o .(2020)使用 HERE Studio 帮助骑自行车的人保持安全。访问日期:2021 年 1 月 17 日
[7]Statistisches Bundesamt(Destatis)(2021)关于我们。访问日期:2021 年 1 月 17 日**
https://www.destatis.de/EN/About-Us/_node.html
面向新数据科学家的首个 Python 库
熊猫& matplotlib 入门
尼泊尔(作者供图)。
介绍
开始学习数据科学令人兴奋,这是一个有益的旅程。这个旅程的一部分是学习数据科学家的工具。
但是,当您刚刚开始学习时,您如何知道要学习什么工具,以及如何开始学习它们呢?
我建议从两个面向新数据科学家的库开始— pandas 和 matplotlib :
- 熊猫用于加载、转换和保存数据。
- matplotlib 用于可视化数据。
这两个库一起提供了足够的东西来开始用 Python 做有意义的数据工作。
熊猫
pandas 是一个 Python 库,用于处理表格数据——包含行和列的数据。如果您使用过 Excel,那么您已经使用过表格数据。
在本文中,我们将使用一个简单的cities
数据集——一个有三行三列的表格数据集:
安装和使用熊猫
您可以使用终端通过 Python 包管理器pip
安装 pandas:
$ pip install pandas
你也可以在 Github 或 Google Colab 上找到一个笔记本,上面有我们在本文中开发的所有代码。
熊猫是通过在 Python 中导入pandas
包来使用的,通常别名为pd
:
import pandas as pd
什么是数据帧?
熊猫的核心是 DataFrame(一个pd.DataFrame
Python 对象),由三部分组成:
- 索引 —一维行标签,
- 列 —一维列标签,
- 数值 —二维数据。
索引和列都是标签——它们告诉我们一行或一列代表什么,比如population
列标签。
创建数据框架
创建数据帧的一种方法是通过 Python 字典,使用:
- 列名作为字典键,
- 作为字典值的数据。
下面我们从字典中创建一个cities
数据帧:
import pandas as pdpd.DataFrame({
'city': ['auckland', 'berlin', 'london'],
'population': [1.6, 3.6, 8.9],
'hemisphere': ['south', 'north', 'north']
})
"""
city population hemisphere
0 auckland 1.6 south
1 berlin 3.6 north
2 london 8.9 north
"""
将 CSV 数据加载到数据帧中
能够从 Python 对象(比如字典和列表)构造数据帧对于构造单元测试的数据非常有用。
创建数据帧的一种更常见的方法是从文件开始,通常是 CSV 文件。这允许我们处理保存在本地机器上的文件中的数据。
Pandas 用pd.read_csv
来处理这个问题,它从我们本地计算机上的 CSV 文件中读取数据。同样的功能也可以用来从互联网上读取数据。
下面我们使用pd.read_csv
从 Github URI 读取数据,读取我们的cities
数据集:
import pandas as pddata = pd.read_csv(
'[https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv'](https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv')
)
"""
city population hemisphere
0 auckland 1.6 south
1 berlin 3.6 north
2 london 8.9 north
"""
这是我们在这篇文章的其余部分直接从公共 URI(比如 URL)加载我们的cities
数据集的方式。
索引、列和值
我们可以将数据帧的三个部分作为初始化的pd.Dataframe
对象的属性来访问:
data.index
# RangeIndex(start=0, stop=3, step=1)data.columns
# Index(['city', 'population', 'hemisphere'], dtype='object')data.values
"""
[['auckland' 1.6 'south']
['berlin' 3.6 'north']
['london' 8.9 'north']]
"""
pandas 为我们创建的索引只是一个范围索引(也称为整数索引)——行被标记为一个整数序列([0, 1, 2]
):
data.index
# RangeIndex(start=0, stop=3, step=1)data
"""
city population hemisphere
0 auckland 1.6 south
1 berlin 3.6 north
2 london 8.9 north
"""
我们可以使用set_index
将其替换为更有意义的索引,将city
列转换为索引:
data.set_index('city')
"""
population hemisphere
city
auckland 1.6 south
berlin 3.6 north
london 8.9 north
"""
我们失去了原来的整数索引[0, 1, 2]
,获得了一个索引city
——太棒了!
在熊猫中选择行和列
数据分析中的一个基本操作是选择—选择行和列。在熊猫身上有两种方法可以做到这一点——loc
和iloc
。
为什么我们需要两种方式来选择?
我们希望以两种方式选择行或列:
- 使用“loc”的标签,
- 使用“iloc”的位置。
两者都要求我们指定行和列(通过标签或位置)——使用:
选择整个行或列。
loc
使用标签
loc
根据行列标签选择。
loc
允许我们使用索引和列的标签——我们使用它来选择基于标签的数据:
# select the berlin row, all columns
data.loc['berlin', :]# select all rows, second colun
data.loc[:, 'population']
iloc
用途位置
iloc
根据行列的整数位置选择。
iloc
允许我们使用行和列的位置——我们使用它来基于位置选择数据:
# select the first row, all columns
data.iloc[0, :]# select all rows, second column
data.iloc[:, 1]
对数据进行排序时,基于位置进行选择非常有用。
iloc
这就是为什么范围索引在熊猫身上没那么有用——我们总是可以使用iloc
根据它的位置来选择数据。
现在我们已经被介绍到了loc
& iloc
,让我们用它们来回答两个关于我们cities
数据集的问题。
奥克兰的人口是多少?
我们可以使用loc
来回答这个问题,选择auckland
行和population
列:
data.loc['auckland', 'population']
# 1.6
我们的第一个城市在哪个半球?
我们可以使用iloc
选择带有0
的第一行,使用loc
选择population
列来回答这个问题:
data.iloc[0].loc['hemisphere']
# north
熊猫中的布尔掩码过滤
数据分析中的另一个基本操作是过滤——基于条件逻辑(if 语句、类似==
的等式和类似>
或<
的不等式)选择行或列。
我们可以用布尔掩码过滤熊猫,布尔掩码可以用条件语句创建:
import pandas as pddata = pd.read_csv('[https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv'](https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv'))# create our boolean mask
# with the conditional 'population < 2.0'
# aka population less than 2.0
mask = data.loc[:, 'population'] < 2.0
"""
city
auckland True
berlin False
london False
Name: population, dtype: bool
"""
布尔掩码是一个由True
或False
组成的数组——如果城市的人口少于 2,这里表示True
。
我们可以使用布尔掩码来过滤数据集,其中loc
- loc
了解如何使用布尔掩码:
subset = data.loc[mask, :]
"""
population hemisphere
city
auckland 1.6 south
"""
如果我们可以用loc
或iloc
选择,为什么我们需要布尔掩码?
使用布尔掩码的强大之处在于我们可以一次选择许多行。
下面我们创建一个基于城市半球的布尔遮罩,然后使用此遮罩选择两行:
mask = data.loc[:, 'hemisphere'] == 'north'
"""
city
auckland False
berlin True
london True
Name: hemisphere, dtype: bool
"""subset = data.loc[mask, :]
"""
population hemisphere
city
berlin 3.6 north
london 8.9 north
"""
熊猫的群体聚集
我们要看的最后一个数据分析操作是聚合。
在 pandas 中,聚合可以通过分组来完成——在数据帧上使用groupby
方法。
两步分组工作流
在熊猫中,聚集分两步进行:
- 基于列创建组,例如通过
hemisphere
, - 对每个组应用聚合函数,如计数或平均。
聚合允许我们估计统计数据,让我们用它来回答几个问题。
每个半球的平均人口是多少?
我们可以用两步工作流程来回答这个问题:
groupby('hemisphere')
按半球来分组,mean()
计算我们每个半球组的平均值(north
和south
)。
import pandas as pddata = pd.read_csv('[https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv').set_index('city')](https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv').set_index('city'))
data.groupby('hemisphere').mean()
"""
population
hemisphere
north 6.25
south 1.60
"""
每个半球的总人口是多少?
回答这个问题的两个步骤是:
回答这个问题的两个步骤是:
1.按hemisphere
、
2 分组。用一个sum
聚合。
data.loc[:, ['population', 'hemisphere']].groupby('hemisphere').sum()
"""
population
hemisphere
north 12.5
south 1.6
"""
将我们的数据保存到 CSV
我们流程的最后一步是将数据以 Excel 友好的 CSV 格式保存到硬盘上:
data.to_csv('groups.csv')
完整的熊猫代码
这是我们对熊猫的第一次观察——我们在上面看到的所有代码都在下面完整地给出了:
import pandas as pd# read dataset from github url
data = pd.read_csv('[https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv').set_index('city')](https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv').set_index('city'))# save cities dataset to local machine
data.to_csv('cities.csv')# select the berlin row, all columns
data.loc['berlin', :]# select all rows, second colun
data.loc[:, 'population']# select the first row, all columns
data.iloc[0, :]# select all rows, second column
data.iloc[:, 1]# What is the population of Auckland?
data.loc['auckland', 'population']# Which hemisphere is our first city in?
data.iloc[0].loc['hemisphere']# select population less than 2
mask = data.loc[:, 'population'] < 2.0
subset = data.loc[mask, :]# northern hemisphere countries
mask = data.loc[:, 'hemisphere'] == 'north'
subset = data.loc[mask, :]# average population in each hemisphere
data.groupby('hemisphere').mean()# total population in each hemisphere
data.loc[:, ['population', 'hemisphere']].groupby('hemisphere').sum()# save to csv file on local computer
data.to_csv('groups.csv')
matplotlib
matplotlib 是一个 Python 库,用于创建数据的可视化。
学习和使用 matplotlib 的挑战之一是它提供了多种绘制数据的方法。掌握 matplotlib 需要了解哪种 API 最适合您的数据和工作流。
我们将使用单个 matplotlib 工作流——我们自己使用最多的工作流。它提供了在同一个图形中绘制多个图表的灵活性,并与 pandas 很好地集成。
安装和使用 matplotlib
可以用 Python 包管理器pip
安装 matplotlib:
$ pip install matplotlib
你也可以在 Github 或 Google Colab 上找到包含所有代码的笔记本。
Matplotlib 通过在 Python 中导入matplotlib
包来使用,通常将模块pyplot
别名为plt
:
import matplotlib.pyplot as plt
matplotlib 图形是由什么组成的?
matplotlib 的核心组件是图形和轴。
一个图形可以有多个轴:
一个常见的混淆点是轴(如 x 或 y 轴)和 matplotlib 轴之间——它们不是一回事!
一个图形可以有多个轴,每个轴是一个单独的绘图或图表。每个轴都有自己的 x 轴和 y 轴(各一个)。
我们可以使用plt.subplots
创建这两个对象——用两个轴创建一个图形:
import matplotlib.pyplot as pltfig, axes = plt.subplots(ncols=2)
我们上面所做的就是创建一个有两个轴的图形——都是空的。
接下来,我们加载熊猫数据,并在第一个坐标轴上创建一个图:
import pandas as pd# run a simple data pipeline - load data from CSV with pandas
data = pd.read_csv('[https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv').set_index('city')](https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv').set_index('city'))# access first axes and plot a line
data.plot('population', ax=axes[0], kind='bar')
自动为 x 和 y 轴制作标签——非常好!
我们的第二个轴仍然是空的——我们可以通过将ax=axes[1]
传递给 DataFrame 上的另一个plot
调用来在其上绘制一些东西:
# access first axes and plot a scatter plot
data.plot('land-area', 'population', ax=axes[1], kind='scatter')
现在我们可以看到数据的两种可视化形式——条形图和散点图。
管道中的最后一步是将图形保存到本地机器上的 PNG 文件中:
fig.savefig('cities.png')
完整的 matplotlib 代码
我们可视化管道的完整代码如下:
import matplotlib.pyplot as plt
import pandas as pd# create one figure with two axes
fig, axes = plt.subplots(nrows=2)# run a simple data pipeline
data = pd.read_csv('[https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv').set_index('city')](https://raw.githubusercontent.com/ADGEfficiency/data-science-south-data/main/cities/cities.csv').set_index('city'))# access first axes and plot a line
data.plot(y='population', ax=axes[0], kind='bar')# access first axes and plot a scatter plot
data.plot('land-area', 'population', ax=axes[1], kind='scatter')# small trick to get x-axis labels to play nice
plt.tight_layout()# save the figure as a png file
fig.savefig('cities.png')
后续步骤
感谢阅读!这两个库还有很多值得学习的地方。
对熊猫的下一步建议是:
- 了解
pd.Series
——另一个用于存储数据的熊猫对象, - 了解如何将数据保存为拼花格式(以及原因),
- 看看我们如何通过一个 groupby 将
.agg
用于不同的聚合。
matplotlib 的建议后续步骤如下:
- 学习使用
plt.plot
绘制数据, - 学会使用
ax.plot
绘制数据, - 查看 seaborn——一个用 pairplot 等图表扩展 matplotlib 的库。
在您熟悉这些工具之后,思考一个项目想法,并完成数据科学项目清单。
如果你想了解更多,一定要看看我为新数据科学家写的书!
最初发表于https://www.datasciencesouth.com。
构建数据科学组合网站的第一步
成为世界级的数据科学家
图片来自 Shutterstock.com
我最近参加了一些讨论,其中数据科学家抱怨获得一份数据科学工作有多不容易。与此同时,如果你像我一样没有任何相关的技术学位,那么你应该想到建立一个自己的投资组合网站,这是讲述自己故事的一种方式,可以增加你被雇主注意到的机会,并使你在市场上的其他数据科学家中脱颖而出。
图片来自 Shutterstock.com
数据科学投资组合应该被视为包含越来越多的真实项目,而不是花哨的设计,不像 web 开发人员或设计师的投资组合。
作为数据科学家,大多数时候,我们只关注数据分析、可视化和建模,从零开始建立一个网站可能有点困难,因为我个人决定从零开始建立,以便在 web 开发领域有广阔的发展空间。然而,有一些动态的、健壮的投资组合构建器,你可以很容易地使用,比如 urspace.io 、 WordPress 、 Squarespace 等等。
在阅读了上面的几行文字后,关于构建这个的想法可以如此伟大和有趣,为了开始,有些事情你绝对需要知道。
入门指南
网站结构
首先,在开始之前,你必须对你想要的网站有一个概念。你想在你的页面上看到和展示什么的大致结构,如何配置潜在的招聘人员和雇主肯定会寻找的东西。你可以上网,搜索和检查一些热门网站的布局。最好的方法是查看其他人的投资组合网站,寻找灵感。我做了很多研究,同时试图建立我的。你可以在这里查看。包括那些帮助过我的人;
朱莉娅·尼库尔斯基
娜塔莎·塞尔瓦拉杰。
定义页面或路线
相当一部分页面是必须包含在你的网站中的。
首页:这是你网站的起始页/登陆页。这应该包括你是谁的简要介绍和一些到你网站上其他页面的直接链接。
关于页面:这是你向世界讲述你的故事、资历、兴趣、技能、旅程,以及其他许多你想说的关于自己的事情的地方。这个页面应该能够以一种个人的和友好的方式吸引和通知你的网站访问者。
作品集页面:如果你真的在建立一个数据科学作品集,那么这一定是你所有页面中最好的。因为我们大多数有抱负的数据科学家都没有在大公司工作的经验,然而,你的项目清单应该真实地显示和告诉我们,你拥有关于部分中强调的所有技能。
在这个页面上,每一个项目,链接到已部署的项目,以及 GitHub 上的代码,如果你已经写了与项目相关的文章,建议添加这样的链接。不管怎样,你应该只添加不同的和独特的项目。Kaggle Titanic Challenge,House Pricing Challenge,Iris Dataset for flower class ification,MNIST 数字分类和其他初学者相关的项目不会出现在页面上,因为这些不会让你比其他数据科学家更好。
来自我的作品集网站的项目
上面的图片显示了我的项目组合中的每个项目是如何被放置在一个容器中的,图片被缩小到特定的大小,项目的简要描述,使用的技能在底部突出显示,有两个链接,一个链接到博客文章,另一个链接到 GitHub 上的代码。这些只是为了让你的投资组合给人留下深刻印象。
博客页面:这可以是一个链接,引导站点访问者到你的博客,也可以是一个包含你所有文章的页面。无论哪种方式,你的博客页面的存在是必需的。
联系我:为了让潜在的雇主联系到你,这个页面应该可以胜任。这应该包含您的联系方式和您的在线状态。至少在 GitHub、LinkedIn 和 Twitter 上有你个人资料的链接。
Precious Kolawole 的 Github 个人资料
这没什么好谈的,因为我们都在走向完美,希望未来几个月会更好,但拥有一个良好的 GitHub 档案,在您的存储库上有许多贡献,会让您成为一名有竞争力的数据科学家。LinkedIn 一直是获取人脉和获得工作的最佳场所之一,拥有出色的个人资料更是加分项。
开始建造
我能够使用 HTML、CSS、Bootstrap、Python 和 Flask 来构建它。然而,如果您对这些编程语言和框架知之甚少,也没有必要惊慌。下面的解释应该能让你入门。
Flask App :关于上面提到的所有页面和路径,这个小型、灵活、轻量级的 python web 框架可用于用 python 创建 web 应用程序。你以前没和弗拉斯克合作过?我为你准备了一个教程,从库安装,实例化应用程序,到在你的本地机器上运行它。检查这里的链接。
在上面的 run.py 文件中,这是我们创建所有页面/部分的地方。然后我们使用渲染模板,一个 flask 函数,称为 Jinja 2 引擎模板包,用于将 HTML 文件添加到我们的页面,显示应用程序模板文件夹中模板文件的输出。
Templates 文件夹:这个文件夹中包含了你的 HTML 文件,这些文件将显示在你的每一个页面上。必须创建一个layout.html,它将作为父模板。这将包含应该在每个页面上重复的布局,其中一个例子是导航栏,它必须实现一次,并且必须在所有页面上看到。这很有帮助,而不是在每个模板中编写整个 HTML 结构。这是 layout.html 的一个例子。
了解这一点后,layout.html 将被扩展,应用程序中的每个页面将围绕不同的主体具有相同的基本布局。下面是一种在模板文件中扩展 layout.html 的方法。
用自己的内容填充块是子模板(例如 home.html)的工作。位于空间内的是你想在你的网站上展示的东西。
看看上面的 layout.html 文件,我们自己并没有写那么多代码。我们有自举!一个强大的集成了 Javascript 的前端框架,有助于在没有大量 CSS 代码的情况下创建漂亮且响应迅速的 web 设计。大约一半的代码来自引导启动模板。看看它,打造你的自己。
静态文件夹:我们的项目目录中必须有这个。静态文件夹必须包含 CSS、JS、images 之类的文件,只是为了给你构建的 HTML 布局添加样式。
好吧!所以,如果你以前熟悉 HTML 和 CSS,开始实现它们,使网页设计符合你的口味。如果没有,我有一些教程给你,你可以从中学习,这些概念很容易掌握。
准备部署了吗?
在实现了你一直想要的作品集网站后,现在是时候让它上线了。
在部署你的投资组合网站时,如果你更喜欢付费的虚拟主机提供商,你可以试试 Hostgator 或 Digital Ocean 。我一直在用 Heroku 做我的部署。我写了一篇逐步介绍如何在 Heroku 上部署你的投资组合网站的文章。一定要去看看。
https://precillieo.medium.com/get-your-python-flask-app-deployed-in-a-swift-6fd653009e4
按照部署的步骤,在添加 Procfile、Requirements.txt 之后,您的项目目录的树应该如下所示。
你干得不错,做到了这一步。如果你需要澄清什么,可以在我的 GitHub 页面上找到构建 mine 的代码。也可以查看网站寻找灵感。这可能是相当累人的建设,但它绝对值得的时间。这是利用你作为数据科学家的职业生涯的一千种方法之一。
你有更多的想法分享,问题和批评。我的投资组合网站的联系我页面有链接,您可以通过这些链接联系到我。让我们从那里开始。我只差一条短信了。
希望这篇文章对你入门有足够的帮助和启发。快乐大厦!
路线图之后学习数据科学或 ML 的第一步
深入研究数据科学和 ML 之前的先决条件和准备工作
来源:https://www.wiplane.com/p/foundations-for-data-science-ml
今年年初,我在数据科学学习路线图(如下图)上发表了思维导图。路线图被广泛接受,那篇文章被翻译成不同的语言,很多人感谢我发表了它。
一切都很好,直到一些有抱负的人指出,有太多的资源,其中许多是昂贵的。Python 编程是唯一一个有很多非常好的课程的分支,但对于初学者来说,它就到此为止了。
关于基础数据科学的几个重要问题让我印象深刻:
- 学会编码后应该做什么?有没有帮助你巩固数据科学基础的主题?
- 我讨厌数学,对我来说,要么有非常基础的教程,要么太深奥。你能推荐一门紧凑而全面的数学和统计学课程吗?
- 有多少数学知识足以开始学习 ML 算法是如何工作的?
- 数据分析或数据科学入门的基本统计主题是什么?
这些问题的答案可以在伊恩·古德菲勒和约舒阿·本吉奥合著的《T4 深度学习》一书中找到。但是对许多人来说,这本书有点太专业和数学化了。
因此,这篇文章的本质是学习数据科学或 ML 的第一步。
数据科学的三大支柱& ML
如果你仔细阅读任何 ML/DS 课程的先决条件或准备工作,你会发现编程、数学和统计学的结合。
忘掉其他人吧,以下是谷歌推荐你在学习 ML 课程前要做的事情:
https://developers . Google . com/machine-learning/速成班/先决条件和准备工作 (CC BY 4.0)
1.基本程序设计
除了商业智能、市场分析、产品分析师等少数角色之外,大多数数据角色都是基于编程的。
我将专注于需要至少一门编程语言专业知识的技术数据工作。我个人更喜欢 Python,因为它的通用性和易学性——这无疑是开发端到端项目的好选择。
一瞥数据科学必须掌握的主题/库:
- 常用数据结构(数据类型、列表、字典、集合、元组)、编写函数、逻辑、控制流、搜索和排序算法、面向对象编程、与外部库协同工作。
- 编写 python 脚本来提取,格式化,并将数据存储到文件或数据库中。
- 处理多维数组,使用 NumPy 进行索引、切片、转置、广播和伪随机数生成。
- 使用 NumPy 等科学计算库执行矢量化运算。
- 使用 Pandas 操作数据—系列、数据帧、数据帧中的索引、比较运算符、合并数据帧、映射和应用函数。
- 使用 pandas 处理数据 —检查空值、输入空值、对数据分组、描述数据、执行探索性分析等。
- 使用 Matplotlib 的数据可视化 API 层次结构,为绘图添加样式、颜色和标记,了解各种绘图以及何时使用它们,线图、条形图、散点图、直方图、箱线图和 seaborn,以进行更高级的绘图。
2.基础数学
对于那些想成为人工智能从业者、数据科学家或深度学习工程师的人来说,数学是必不可少的,这是有实际原因的。
1.表示数据的线性代数
本课程中关于向量范数的讲座图片:https://www.wiplane.com/p/foundations-for-data-science-ml
ML 本质上是数据驱动的;数据是机器学习的核心。我们可以把数据看作是向量— 遵循算术规则的对象。这让我们理解了线性代数的规则是如何操作数据数组的。
2.训练 ML 模型的微积分
课程中关于梯度下降的讲座图片:https://www.wiplane.com/p/foundations-for-data-science-ml
如果你认为模型训练是“自动”发生的,那你就错了。微积分是大多数 ML 和 DL 算法学习的驱动力。
最常用的优化算法之一——梯度下降——是偏导数的应用。
模型是某些信念和假设的数学表示。据说,它首先学习(近似)如何提供数据、如何生成数据的过程(线性、多项式等),然后基于所学习的过程进行预测。
重要话题包括:
- 基础代数— 变量、系数、方程、函数—线性、指数、对数等。
- 线性代数— 标量、向量、张量、范数(L1 & L2)、点积、矩阵的类型、线性变换、用矩阵符号表示线性方程、利用向量和矩阵解决线性回归问题。
- 微积分— 导数和极限、导数规则、链规则(用于反向传播算法)、偏导数(用于计算梯度)、函数的凸性、局部/全局最小值、回归模型背后的数学、从头开始训练模型的应用数学。
3.基本统计
如今,每个组织都在努力成为数据驱动型组织。为了实现这一目标,分析师和科学家需要以不同的方式使用输入数据,以推动决策制定。
描述数据—从数据到见解
数据总是原始而丑陋的。最初的探索告诉您缺少什么,数据是如何分布的,以及清理数据以满足最终目标的最佳方式是什么。
为了回答已定义的问题,描述性统计使您能够将数据中的每个观察结果转化为有意义的见解。
量化不确定性
此外,量化不确定性的能力是任何数据公司都非常重视的最有价值的技能。了解任何实验/决策的成功机会对所有企业都非常重要。
这里有一些构成最低限度的主要统计数据:
图片来自泊松分布讲座—https://www.wiplane.com/p/foundations-for-data-science-ml
- 位置估计值——平均值、中间值和其他变量。
- 可变性的估计
- 相关性和协方差
- 随机变量—离散和连续
- 数据分发— PMF、PDF、CDF
- 条件概率—贝叶斯统计
- 常用的统计分布——高斯分布、二项式分布、泊松分布、指数分布。
- 重要定理-大数定律和中心极限定理。
图片来自泊松分布讲座—https://www.wiplane.com/p/foundations-for-data-science-ml
- 推断统计— 一种更实用、更高级的统计分支,有助于设计假设检验实验,推动我们深入理解指标的含义,同时帮助我们量化结果的重要性。
- 重要测试— 学生的 t 检验、卡方检验、ANOVA 检验等。
每一个初级数据科学爱好者都应该在深入任何核心数据科学或核心 ML 课程之前关注这三大支柱
学习上述内容的资源——寻找紧凑、全面而又负担得起的课程。
https://www . freecodecamp . org/news/data-science-learning-roadmap/
我的学习路线图也告诉你要学什么,它还载有你可以报名参加的资源、课程和项目。
但是在推荐的资源和我绘制的路线图中有一些不一致的地方。
数据科学或 ML 课程的问题
- 我在那里参加的每一门数据科学课程都要求学生对编程、数学或统计有相当好的理解。例如,吴恩达最著名的 ML 课程也非常依赖于对向量代数和微积分的理解。
- 大多数涵盖数据科学的数学和统计学的课程只是 DS/ML 所需概念的清单,没有解释它们如何应用以及它们如何被编程到机器中。
- 有一些特殊的资源可以深入研究数学,但我们大多数人都不适合数学,学习数据科学不需要成为金牌得主。
wiplane.com 维普兰学院
所以,我决定让步,全靠自己。我花了 3 个月的时间开发了一个课程,为你的职业生涯提供了一个坚实的基础。
- 数据分析师
- 数据科学家
- 或者 ML 从业者/工程师
在这里,我向您介绍数据科学的 基础或 ML—学习数据科学和 ML 的第一步
那是我决定发射的时候!
这是一门全面而紧凑且经济实惠的课程,不仅涵盖了所有的基本要素、先决条件、&准备工作,还解释了每个概念如何在计算上和程序上使用(python)。
不仅如此,我还会根据您的意见每月更新课程内容。在这里了解更多。
早鸟优惠!
我很高兴启动本课程的预售,因为我目前正在录制和编辑 2-3 个模块的最后部分,这些模块也将在 9 月的第一周上线。
获取早鸟优惠,有效期至 2021 年 8 月 30 日。
作为集成学习算法的鱼群
总的来说是准确的
动物群体大于它们各部分的总和。当蚁群建造了一个坚固且通风良好的土堆时,单个的白蚁毫无头绪地四处游荡。孤鹤迷失方向,而群鸟成功迁徙。在认知复杂性的范围内,我们经常看到群体层面上出现成员单独无法做到的行为。这怎么可能?
我花了我的博士学位来研究金色闪光鱼——一种普遍无望且不太聪明的生物——如何形成能够优雅地躲避捕食者的群体。我阅读了几十篇文章和教科书,进行了实验,分析了数据,并与理论家合作,试图弄清楚当谈到鱼时,1+1=3,而不是 2。
当我离开学术界进入数据科学领域时,我获得的所有知识似乎注定要在我大脑的某个角落成为一堆尘封的事实。但是当我开始我的数据科学教育时,我惊讶地看到我研究的 中的 决策与 集成学习 算法 中的 决策之间有一种奇怪的相似之处。
这篇文章将向你展示弱学习者的集合——无论他们是鱼还是决策树——如何一起形成一个精确的信息处理器。
机器
让我们首先讨论机器学习方面,因为你可能比动物更熟悉算法!集成学习方法使用一组模型来生成预测,而不是一个单一模型。这个想法是模型预测中的误差相互抵消,导致整体预测更加准确。
在下面的示意图中,我们的集合是一组灰色的盒子,每个盒子都是一个模型。为了生成输入的预测值,输入被发送到每个模型,该模型生成一个预测。然后,通过平均(用于回归)或多数投票(用于分类),这些单独的预测被缩减为一个集合预测。
作者图片
一种流行的集成方法是 随机森林 ,这是一种由几十或几百棵决策树组成的模型。虽然有很多方法来配置如何组装森林,但一般的过程是每棵树都根据引导的观察和特征的随机子集进行独立训练。(如果我们对每棵树使用相同的数据,我们每次都会创建相同的树!)
结果是模型的集合,每个模型对训练数据的理解略有不同。这种变化至关重要。单个决策树很容易变得过度适应它们的训练数据,沉迷于它们样本中的模式,而这些模式在更广阔的世界中不一定存在。但是因为集合由许多树组成,当计算集合预测时,这些误差倾向于彼此抵消。
该理论
随机森林增强的准确性可以概括为群众的智慧。这个概念可以追溯到 1906 年马萨诸塞州普利茅斯的一个牲畜交易会上,当时举办了一场猜公牛体重的比赛。近 800 名农民给出了他们最好的估计。统计学家弗朗西斯·高尔顿爵士后来检查了这些猜测,并观察到尽管个人估计差异很大,但估计的平均值比任何个人猜测都更准确。高尔顿继续在他著名的《大众之声》论文中正式阐述他的理论。
要让群众的智慧发挥作用,有两个关键要求。首先是个人必须改变他们的信息。如果每个人都有相同的信息,团队的决定不会比个人的更准确。这甚至会导致群体成员对他们的回音室过于自信,从而导致一般的不太准确的决策。[1]
第二个要求是个人评估必须独立于和。如果这 800 名农民在投票前与他们的邻居商议,独特观点的数量将会减少到几百个,甚至可能只有几十个,因为人们的观点开始相互影响。个性张扬的人的意见会比沉默寡言的人的意见更有分量;罕见的信息将被丢弃,以利于常识。
在某种程度上,这些农民就像一个随机的森林,需要几十年的时间来培养。在他们的一生中,每个农民都学会了如何将牛的各种特征——角的大小、肩高——与体重对应起来。在交易会上,每个农民都选择了一个新的数据点,并独立地进行估算。然后,高尔顿将他们的回答汇总成一个最终的预测,从而完成了类比。
鱼
虽然群众的智慧可以解释牛展会,但对于我们的 shiners 来说,这个故事变得更加微妙。随机森林并不是描述鱼群的正确算法,一个主要原因是:一条鱼所拥有的关于其环境的信息与其邻居有很强的相关性。
想想下面的图片,一所学校有 150 个金闪闪发光的人。使用光线投射算法对每个发光器的视野进行了近似,只有实际离开该组的光线被着色为白色。
图片来自罗森塔尔等人 2015 年的补充信息
首先跳出来的是,学校内部是外界信息的死区——这些鱼只看到其他鱼。第二件要注意的事情是,即使对于 T2 看到外面的闪光者来说,彼此附近的个体也在接收关于他们周围环境的基本相同的信息。
当只有极少数关于外部世界的独立数据点时,像这样的一群人怎么可能做出明智的决定,决定是向左还是向右,探索食物还是躲避捕食者?(然后协调那几十个群龙无首的成员!)然而,尽管个体的信息在空间上是自相关的,这阻碍了群体的智慧,但还是有一些闪亮的群体有效地找到了避难所和调节了对风险的反应。
不幸的是,这些问题没有简单的答案!集体行为领域正在努力试图理解简单的局部互动如何导致复杂的群体行为。但我认为有两类机器学习算法可以解释鱼群如何做它们所做的一些方面。
首先是 助推合奏学习 。随机森林使用 bagging,这涉及到并行地独立训练每个模型。另一方面,像 AdaBoost 和 XGBoost 这样的方法依次训练模型,后面的模型从前面模型的错误中学习。成群游动的鱼很快学会从其他鱼的错误中识别出捕食者,而理解环境线索的鱼通常最终会决定群体运动的方向。
第二种可能性是鱼群就像一个巨大的神经网络。(从生物神经元到人工神经网络,再到鱼群……我们又兜了一圈!)当谈到避免被捕食时,许多鱼类会做出惊吓反应,即一种超快速、反射性的逃离令人惊恐的刺激的爆发。[2]这些反应是会传染的,通常会导致一连串的惊吓,其速度比攻击捕食者还要快。
令人震惊的瀑布。图片来自罗森塔尔等人 2015
这里有趣的一点是,群体成员的输出(即它们是否会惊吓)作为邻近鱼类的输入来决定它们是否应该惊吓。特别是对于在群体深处的鱼来说,几乎没有个人信息来验证波浪是假警报还是迎面而来的捕食者,对这些社会线索做出适当的反应可能意味着生死。
我们通常认为人工神经网络是模仿生物神经网络,但在某种程度上,整个群体在处理关于其环境中风险的信息时充当一组神经元。但更令人着迷的是,这些神经元可以改变它们网络的结构,从而改变信息的处理方式。
在我的一篇论文中,我和我的同事展示了闪灵人通过改变个体之间的间距来调节他们对威胁的反应,而不是对是否对邻近的惊吓做出反应的内部计算。这意味着,群体结构本身,而不是个人,控制着随机的启动是螺旋上升为全面的级联,还是悄无声息地失败。
神经网络的一个神经网络决定去哪里吃饭。作者图片
结论
动物群体如何完成个体无法完成的行为?这是集体行为领域整天思考的中心问题,集合了生物学、心理学、物理学和计算机科学试图回答这个问题。在这篇文章中,我们讨论了一个简单的集体智慧的例子,在这个例子中,对一头牛体重的独立估计导致了一个更准确的总体估计。然后我们浏览了鱼群集体计算的表面,鱼群的无定形结构在处理周围信息时不断变化。
有兴趣了解更多信息吗?看看狒狒如何民主地做出运动决定,创新行为在野生鸟类中代代相传,或者黏菌如何通过优化资源分配来重建东京地铁图。一定要去马克斯·普朗克动物行为研究所的集体行为部看看最新的很酷的集体行为研究。
最好,
马特
脚注
1.该理论
如果你从未在网上遇到不同的世界观,或者你只看到它被框定为属于一个白痴,那么你很可能在回音室。这种情况在很大程度上是不可避免的,因为社交网络往往会自我隔离,这意味着你需要寻找更客观的世界观所需的不同观点。
2.鱼
为了在杂草中获得超级,实际上可能有多条神经通路用于启动,其中一些具有更精细的运动控制。至少,发光的人会因不同的强度而吃惊。但是当量化一个群体中的信息传播时,将震惊二值化为“是的,这条鱼受惊了”和“不,他们没有”是一个很好的近似
鱼重预测(初学者回归分析)——第一部分
如何使用顶级线性 ML 算法(线性回归、套索回归和岭回归)构建 ML 回归模型
雷切尔·希斯科在 Unsplash 上拍摄的照片
目录
简介
第 1.1 部分——构建 ML 模型管道。
第 1.2 部分——分析算法和方法。
∘ 什么是线性模型?
∘ 算法对比
∘ 评价
结论
参考文献
简介
今天,我们将使用线性模型,根据鱼的物种名称、垂直长度、对角线长度、交叉长度、高度和对角线宽度来预测(估计)鱼的重量。我将介绍解决问题的顶级城镇方法,我在之前的文章中解释过。首先在 1.1 部分我将建立一个模型,然后在 1.2 部分我将尝试解释每个算法和方法是如何工作的。这是一个适合初学者的回归分析问题。了解这类问题的主要构建原则和方法,有助于构建自己的 ML 回归模型如(房价预测等。)
第 1.1 部分—构建 ML 模型管道。
一般来说,构建 ML 模型分为 8 个步骤:如下图所示。
通常,数据科学家将 80%的时间花在前三步(也称为解释性数据分析-EDA)。大多数 ML 应用程序都遵循这一流程。简单应用和高级应用的区别在于 EDA 步骤。所以我们就按照上面提到的流水线,以解决权重预测问题为例。
第一步:收集数据
数据是可以从 Kaggle 下载的公共数据集。
**import** pandas **as** pd
**import** seaborn **as** sns
**import** matplotlib.pyplot **as** plt
**from** itertools **import** combinations
**import** numpy **as** np
data **=** pd**.**read_csv("Fish.csv")
第二步:可视化数据(问自己这些问题并回答)
- 数据看起来怎么样?
data**.**head()
作者图片
- 数据是否有缺失值?
data**.**isna()**.**sum()
作者图片
注意:如你所见,在这种情况下,因为问题是针对初学者的,所以我们没有丢失值,然而,情况并不总是这样。在接下来的文章中,我们将有丢失值的数据,并有可能理解如何处理它。
- 数字特征的分布是什么?
data_num **=** data**.**drop(columns**=**["Species"])
fig, axes **=** plt**.**subplots(len(data_num**.**columns)**//**3, 3, figsize**=**(15, 6))
i **=** 0
**for** triaxis **in** axes:
**for** axis **in** triaxis:
data_num**.**hist(column **=** data_num**.**columns[i], ax**=**axis)
i **=** i**+**1
正如你所看到的,发行版是不错的。目标变量(权重)似乎有点不平衡,可以通过一些方法来平衡这些值。这是一个有点高深的话题,让我们暂时忽略它。
- 目标变量(重量)相对于鱼种的分布情况如何?
sns**.**displot(
data**=**data,
x**=**"Weight",
hue**=**"Species",
kind**=**"hist",
height**=**6,
aspect**=**1.4,
bins**=**15
)
plt**.**show()sns**.**pairplot(data, kind**=**'scatter', hue**=**'Species');
关于物种的目标变量分布表明,有些物种,如狗鱼,与其他物种相比具有巨大的重量。这种可视化为我们提供了关于“物种”特征如何用于预测的额外信息。
- 目标变量和特征之间的相关性是什么?
plt**.**figure(figsize**=**(7,6))
corr **=** data_num**.**corr()
sns**.**heatmap(corr,
xticklabels**=**corr**.**columns**.**values,
yticklabels**=**corr**.**columns**.**values, annot**=True**)
plt**.**show()
列的成对相关显示所有数字特征与权重正相关。这意味着长度或宽度越高,重量就越大。这似乎也符合逻辑。
第三步:清理数据
**from** sklearn.model_selection **import** train_test_split
**from** sklearn.compose **import** make_column_transformer
**from** sklearn.preprocessing **import** OneHotEncoder, StandardScaler
**from** sklearn.linear_model **import** LinearRegression, Ridge, Lasso
**from** sklearn.metrics **import** mean_squared_error, mean_absolute_error, r2_score
ct **=** make_column_transformer(
(StandardScaler(),['Length1','Length2','Length3','Height','Width']), *#turn all values from 0 to 1*
(OneHotEncoder(handle_unknown**=**"ignore"), ["Species"])
)
*#create X and y values*
data_cleaned **=** data**.**drop("Weight",axis**=**1)
y **=** data['Weight']
x_train, x_test, y_train, y_test **=** train_test_split(data_cleaned,y, test_size**=**0.2, random_state**=**42)
print(x_train**.**shape, x_test**.**shape, y_train**.**shape, y_test**.**shape)X_train_normal **=** pd**.**DataFrame(ct**.**fit_transform(x_train))
X_test_normal **=** pd**.**DataFrame(ct**.**transform(x_test))
使用 OneHotEncoder 将物种列转换为 7 个特征。数字特征被缩放是因为线性模型喜欢缩放。(我将在文章的 1.2 部分解释细节)
第四步:训练模型
**def** models_score(model_name, train_data, y_train, val_data,y_val):
model_list **=** ["Linear_Regression","Lasso_Regression","Ridge_Regression"]
*#model_1*
**if** model_name**==**"Linear_Regression":
reg **=** LinearRegression()
*#model_2*
**elif** model_name**==**"Lasso_Regression":
reg **=** Lasso(alpha**=**0.1,tol**=**0.03)
*#model_3*
**elif** model_name**==**"Ridge_Regression":
reg **=** Ridge(alpha**=**1.0)
**else**:
print("please enter correct regressor name")
**if** model_name **in** model_list:
reg**.**fit(train_data,y_train)
pred **=** reg**.**predict(val_data)
score_MSE **=** mean_squared_error(pred, y_val)
score_MAE **=** mean_absolute_error(pred, y_val)
score_r2score **=** r2_score(pred, y_val)
**return** round(score_MSE,2), round(score_MAE,2), round(score_r2score,2)model_list **=** ["Linear_Regression","Lasso_Regression","Ridge_Regression"]
result_scores **=** []
**for** model **in** model_list:
score **=** models_score(model,X_train_normal,y_train, X_test_normal,y_test)
result_scores**.**append((model, score[0], score[1],score[2]))
print(model,score)
在上面的代码中,我们训练了不同的模型,并测量了均方误差(MSE)、平均绝对误差(MAE)、R 得分的准确性。
第五步:评估
df_result_scores **=** pd**.**DataFrame(result_scores,columns**=**["model","mse","mae","r2score"])
df_result_scores
最佳模型的 MSE 和 MAE 值低,R 值高。结果显示,在该数据集中,简单线性回归的表现优于 Lasso 回归和岭回归。
步骤 6:超参数调整
在这种情况下,基本线性回归模型的超参数可以被认为是学习率。它被实现为一个 SGDRegressor ,它更新学习率和权重。所以现在最好是为山脊或套索做超参数调整。让我们做岭回归,看看它是否会击败简单线性回归的分数。
from scipy.stats import loguniform
from sklearn.model_selection import RepeatedKFold
from sklearn.model_selection import RandomizedSearchCVspace = dict()
space['solver'] = ['svd', 'cholesky', 'lsqr', 'sag']
space['alpha'] = loguniform(1e-5, 50)
model = Ridge()cv = RepeatedKFold(n_splits=5, n_repeats=3, random_state=1)search = RandomizedSearchCV(model, space, n_iter=100,
scoring='neg_mean_absolute_error', n_jobs=-1, cv=cv, random_state=42)
result = search.fit(X_train_normal, y_train)print('Best Score: %s' % result.best_score_)
print('Best Hyperparameters: %s' % result.best_params_)
最好成绩:-75 分。36860.78868688667
最佳超参数:{'alpha': 0.24171039031894245,' solver': 'sag'}
现在让我们拟合这些超参数,看看结果。
reg = Ridge(alpha=0.24171039031894245, solver ="sag" )
reg.fit(X_train_normal,y_train)
pred = reg.predict(X_test_normal)
score_MSE = mean_squared_error(pred, y_test)
score_MAE = mean_absolute_error(pred, y_test)
score_r2score = r2_score(pred, y_test)
to_append = ["Ridge_hyper_tuned",round(score_MSE,2), round(score_MAE,2), round(score_r2score,2)]
df_result_scores.loc[len(df_result_scores)] = to_append
df_result_scores
超参数改进了以前的缺省岭结果,但是,它仍然不如简单的线性回归。
第七步:选择最佳模型和预测
*# winner model*
reg **=** LinearRegression()
reg**.**fit(X_train_normal,y_train)
pred **=** reg**.**predict(X_test_normal) plt**.**figure(figsize**=**(18,7))
plt**.**subplot(1, 2, 1) *# row 1, col 2 index 1*
plt**.**scatter(range(0,len(X_test_normal)), pred,color**=**"green",label**=**"predicted")
plt**.**scatter(range(0,len(X_test_normal)), y_test,color**=**"red",label**=**"True value")
plt**.**legend()
plt**.**subplot(1, 2, 2) *# index 2*
plt**.**plot(range(0,len(X_test_normal)), pred,color**=**"green",label**=**"predicted")
plt**.**plot(range(0,len(X_test_normal)), y_test,color**=**"red",label**=**"True value")
plt**.**legend()
plt**.**show()
为了评估 MSE、MAE 和 R2score,我们需要将预测和实际预测可视化。为什么?因为只有 MSE 或 MAE 分数,我们不能理解模型有多好。所以在上面的可视化中,预测和真值真的很接近。这意味着模型运行良好。
第 1.2 部分— 分析算法和方法。
在这一部分,我将解释以上算法、方法和评估背后的所有理论部分。
什么是线性模型?
术语线性模型意味着模型被指定为特征的线性组合。线性回归、套索回归和岭回归都是线性算法。
- 什么是线性回归?
线性回归是基于自变量 x 预测目标变量 Y 的 ML 监督学习算法,我们举一个简单的例子,计算一下如何弄清楚它的工作原理。比如 X 是工作经验,Y 是工资。
作者图片
从这个形象化的例子中,我们可能很容易理解工作经验和薪水之间的关系——如果一个人有更多的经验,他们会赚更多的钱。
我们有一个线性回归的假设函数
其中 a 和 b 是可训练参数(也称为系数、权重)。
a-y 轴上的截距
b —是一个斜率
目标:找到 a 和 b,使得我们最小化成本函数,这与普通的最小二乘法相同(在 Sklearn 中)
在下图中,我们可以直观地了解算法是如何工作的。在第一个特征中,我们有一个假设函数 h(x) = 32,然后计算 OLS,我们更新参数并生成假设函数 h(x) = 1.6x +29,最后它达到 h(x) = 3.6 +20。对于每个参数更新,目标是最小化 OLS。
作者图片
我们如何更新 a 和 b 的值来最小化 MSE?
我们使用梯度下降算法更新 a 和 b,直到收敛。但是首先什么是梯度?
梯度衡量的是当你稍微改变输入时,函数的输出会有多大的变化——Lex frid man(MIT)
简而言之,梯度测量关于成本函数的所有权重的变化。它是一个函数的斜率,斜率越高,模型学习得越快。但是如果梯度为零,权重不再更新,因此算法停止学习。
a 由第二部分更新,第二部分是学习率和梯度乘法。学习率对找到局部最小值有巨大的影响。当学习率太大时,它会导致在函数的局部最小值之间来回跳跃,而如果学习率太低,它将达到局部最小值,但会花费太多时间。
- 拉索回归
Laso 是线性回归的一个微小修改。它执行 L1 正则化,这意味着它添加了相当于系数幅度绝对值的惩罚。我们为什么需要它?因为它最终将大的权重降低到小的,小的权重降低到几乎为零。理论上,当我们在训练数据中有很多特征并且我们知道并非所有特征都重要时,可以使用这种方法。Lasso 回归将有助于从大量特征中识别出几个最重要的特征。
- 岭回归
岭回归也是使用 L2 正则化对线性回归的轻微修改,这意味着它从权重平方值的总和中对模型进行惩罚。因此,这导致系数的绝对值减小,并且具有均匀分布的系数。我们为什么需要这个?如果我们有一些特征,并且我们知道它们都可能影响预测,我们可以在这种情况下使用岭回归。
所以线性回归是没有正则化的(对参数没有惩罚)。它有时会对某些特征赋予较高的权重,从而导致小数据集中的过度拟合。这就是为什么使用套索回归(与 L1 正则化相同)或岭回归(L2 正则化)模型来调整独立变量的权重。一般来说,如果数据特征的数量远小于样本数量(#特征<< #rows) then it is likely that simple linear regression would work better. However, if a number of features are not much less than a number of samples it will tend to have high variance and low accuracy, in that case, Lasso and Ridge are more likely to work better.
Comparison of the Algorithms
image by author
评估
所有回归类型的模型都有相同的评估方法。最常见的是均方误差、平均绝对误差或 R 评分。我们举个例子,手工算一下每个分数。
y_true = [1,5,3]
y_pred = [2,3,4]
MSE(y_true,y _ pred)= 1/3 *[(1–2)+(5–3)+(3–4)]= 2()
MAE(y_true,y _ pred)= 1/3 *[| 1–2 |+| 5–3 |+| 3–4 |]= 1.33
R2score(y_true,y _ pred)= 1—[(1–2)+(5–3)+(3–4)]/[[(1–3)+(5–3)+(3–3)]]= 0.25
我们的目标是找到一个具有低 MSE 或 MAE 和高 R2 得分(最好是 1)的模型。
结论
没有现成的公式来检测每个任务和数据集选择哪种算法。这就是为什么尝试几种算法并对每一种算法进行评估仍然很重要。但是,我们需要知道每个算法背后的直觉。正如理论所说,由于我们有大约 160 个数据点,只有 12 个特征,线性回归更有可能工作得更好,事实也是如此。然而,由于在训练特征之间有很高的线性相关性,这就是为什么 Lasso 和 Ridge 也有不错的结果。在未来的文章中,我将对不同种类的数据集进行同样的尝试,让我们看看分数将如何变化。
我的 GitHub 库链接的代码是这里是。
参考
[1]【www.geeksforgeeks.org】T2, ML |线性回归(2018)
[2] GAURAV SHARMA,5 您应该知道的回归算法—入门指南! (2021)
【3】徐文伟,Sklearn 中的线性回归、套索、山脊、ElasticNet 有什么区别? (2019)
[4] Niklas Donges,梯度下降:机器学习最流行算法的介绍 (2021)
[5] L.E. MelkumovaS.Ya. Shatskikh,比较岭估计和套索估计用于数据分析 (2017)第三届国际会议“信息技术和纳米技术
[6] Jason Brownlee,随机搜索和网格搜索的超参数优化 (2020),机器学习掌握
[7]Aarshay Jain,Python 中脊和套索回归的完整教程 (2016)
[8]scikit-learn.org, 1.1。线性模型
[9]scikit-learn.org, 3.3.4。回归指标
费雪线性判别式:直观解释
机器学习基础
线性判别分析的基础 Fisher 线性判别的直观解释
塞缪尔·伯克在 Unsplash 上的照片
LDA 是一种广泛使用的基于 Fisher 线性判别式的降维技术。这些概念是机器学习理论的基础。在本文中,我将介绍一个使用 Fisher 线性判别式的分类器示例,并推导出 Fisher 准则的最佳解决方案。最后,我将 LDA 作为一种降维技术与 PCA 进行了比较。
介绍
训练分类器包括找到最佳分离数据的权重向量。如何定义这种分离是分类器不同的原因。在最小二乘分类器中,我们找到最小化均方误差的向量,并通过优化算法(如随机梯度下降)进行优化。在 Fisher 的线性判别式中,我们试图根据分布来分离数据,而不是根据每个数据点来调整权重向量。
费希尔线性判别式
为了理解线性判别分析,我们需要首先理解费希尔的线性判别。
Fisher 的线性判别式可以用作监督学习分类器。给定标记的数据,分类器可以找到一组权重来绘制决策边界,从而对数据进行分类。 Fisher 线性判别式试图找到最大化投影数据类别之间的间隔的向量。最大化“分离”可能会有歧义。Fisher 线性判别式遵循的标准是最大化投影均值的距离,最小化投影类内方差。
我们的使命
让我们设置一个问题,如果你能完成它,你就会理解费希尔的线性判别式!
作者图片
这里有两个二元高斯模型,它们具有相同的协方差矩阵和不同的均值。我们希望找到最能分离数据投影的向量。让我们画一个随机向量,并绘制投影。
作者图片
请记住,我们看到的是数据在向量(权重向量和数据矩阵的点积)上的投影,而不是决策边界。数据在这个随机权重向量上的投影可以绘制成直方图(右图)。正如您在将数据投影到矢量上并绘制直方图时所看到的,这两类数据没有很好地分开。我们的目标是找到右边图像中两个分布的最佳分割线。
为了分离这两个分布,我们可以首先尝试最大化投影平均值之间的距离,这意味着平均而言,这两个分布彼此尽可能远。让我们在两个平均值之间画一条线,并将投影的直方图绘制到这条线上。
作者图片
这已经好多了,但是数据的投影还没有完全分离。为了完全分离它们,Fisher 线性判别式在最大化均值间投影的同时最小化投影的类内方差。它试图最大化我们之前讨论的方法来分离它们,但是也试图使分布尽可能紧密。这样可以更好地分离,如下图所示。
作者图片
如你所见,数据的投影被很好地分开了。我们可以从权重向量中取一个正交向量来创建决策边界。决策边界告诉我们,在边界的任何一边,数据都可以被预测为一个或另一个类。对于具有相同协方差矩阵的多元高斯分布,这产生了最佳分类器。
费希尔标准
既然我把问题形象化了,我们就可以用方程的形式正式表达这些概念。
作者图片
最大化费希尔准则包括找到最大化上述等式的权重向量。最大化这个方程相当于我们之前看到的。最大化意味着最大化分子(投影均值之间的距离)和最小化分母(类内方差)。我们可以在等式中代入均值和协方差,并将费雪准则改写如下。
作者图片
上述等式在权重向量 w 的分子和分母中具有二次形式。我们可以通过微分和等于零来使 J 相对于 w 最大化。
作者图片
我们不关心标量,因为我们总是可以在以后规格化向量。上面突出显示的项是标量,因此被吸收到常数α或最后一行的比例符号中。由此,我们知道,当权重向量 w 与上述表达式成比例时,它使费雪准则最大化。在前面的例子中,我用这个比例找到了费雪的判别线性方向。
线性判别分析(LDA)
之前,我们将数据投影到权重向量上,并绘制了直方图。这种从 2D 空间到直线的投影降低了数据的维数,这就是 LDA。LDA 使用 Fisher 线性判别式来降低数据的维数,同时最大化类别之间的分离。它通过最大化均值之间的距离和最小化类内方差来做到这一点。
PCA 与 LDA
那么 LDA 与其他降维技术相比如何呢?另一种非常常见的降维方法是 PCA,它可以最大限度地将信息量传递到更小的维度上。PCA 使用通过奇异值分解找到的主成分,而不是 Fisher 的线性鉴别方向。主成分是最大化投影数据变化的方向(这不考虑数据的类别)。LDA 会考虑数据中的类别,而 PCA 则不会。
选择什么样的降维技术需要你正确理解这些技术和你正在处理的问题。希望这篇文章对你的第一部分有所帮助。
结论
在这篇文章中,我解释了 Fisher 的线性判别式,以及如何将它用作分类器和降维。我强调费希尔的线性判别式试图在低维空间中最大化类的分离。这与 PCA 等其他降维技术有着本质的不同,它不考虑数据的类成员关系。
支持我
希望这对你有所帮助,如果你喜欢它,你可以跟随我!
您也可以成为 中级会员 使用我的推荐链接,访问我的所有文章以及更多:https://diegounzuetaruedas.medium.com/membership
你可能喜欢的其他文章
利用广义加性模型拟合非线性关系
利用 pyGAM 包
图片来自 unsplash
简介
各种变量之间的真实世界关系大多是非线性的,理解这种关系对于最佳预测是至关重要的。谁有这种关系的洞察力,谁就能正确预测市场,并为任何低迷做好准备。它不仅对商业分析至关重要,对临床研究、社会研究、工程应用等也同样重要。在本文中,我将向读者介绍广义可加模型(GAM)的实现,并与线性、多项式和样条回归模型进行比较。读者就能理解它对正确预测未来趋势的重要性。
简要背景
线性和多项式回归是回归分析的基础。对于非线性关系,多项式拟合工作得非常好,并且当存在对过度拟合的优化时,可以预见下一个数据点。过度拟合是机器学习爱好者的噩梦。当多项式过度拟合局部数据点时,它在进行预测时会变得混乱。基本上,过度拟合的模型不能正确预测,并且在应用测试数据时表现不佳。在这些情况下,线性模型可以是一个很好的替代品,并且可以降低误差。对于回归模型,还有其他问题,如异方差。如果有人感兴趣,我还有另外一篇文章。
先说多项式和样条回归的利弊。多项式回归是非线性曲线拟合的基本分析方法。其背后的数学比简单的线性回归更复杂,但比样条回归更简单。多项式回归受到龙格效应的影响,即数据集的端点与模型不同步,当应用回归时,结果变化很大。当在模型中使用高阶多项式时,这种现象尤其明显。多项式回归的一个更复杂的版本是样条回归。这种方法首先识别中间节点,然后使用数据点找到节点之间的最佳拟合。当使用 3 节时,这些点通常是第 25、50 和 75 个百分点。读者可以阅读下面的文章,以获得更多关于样条回归的见解。
一种更灵活的建模技术是广义加性模型,它可以在不指定节点位置的情况下部署。维基百科对它的定义如下:
一种广义线性模型,其中线性响应变量线性依赖于某些预测变量的未知光滑函数,人们的兴趣集中在对这些光滑函数的推断上。
来源:维基百科
简而言之,这里的结果不是加权和,而是一些任意函数的和。在本文中,我将展示使用多项式、样条和 GAM 拟合非线性关系的区别。
数据集
出于用 python 实现的目的,我将利用来自 Kaggle 的鱼数据集。给定变量之间存在非线性关系。数据集可供公众使用,许可在这里描述(Apache 2.0)。
使用 pyGAM 实现
首先,需要安装 pyGAM 包。鱼的数据提供了鱼的重量和宽度之间的下列相关性。
作者图片
我有兴趣使用多项式拟合、样条拟合和 GAM 来拟合这种非线性依赖关系。
多项式回归
感兴趣的变量之间的关系非常明显。鱼的宽度越大,鱼的重量就越重。数据可以线性拟合,但标准误差会很高。此外,由于数据集的性质,还会存在异方差。这似乎是一种锥形关系,数据的变化最初非常紧密,但后来,偏差变得很大。让我们用二阶多项式来拟合这个模型。
二阶多项式拟合。作者图片
看起来曲线很适合给定的数据。这种趋势似乎在增加,无论宽度值有多高,由于二阶相关性,重量也会高很多。但是,情况总是这样吗?一条宽 9 厘米的鱼的重量是~1700 克吗?我们能做出更好的模型吗?
样条回归
让我们使用 3 个自由度和节点之间的二阶多项式在同一数据集上实现样条回归。
与多项式回归相比,拟合稍好,因为 R 平方值增加了。下图显示的拟合与上面的多项式模型非常相似。这种配件在较高的一侧具有某种展平效果。在较低的一边,它表现不好,因为趋势是向上的。如果鱼的宽度小于 1 厘米,它的重量不能高于 1 厘米宽的鱼。
样条回归。作者图片
广义可加模型
在这种方法中,我们不需要定义结。这种决策具有灵活性,多项式字符串会自动绑定在一起。这可以使用 pyGAM 包来实现。当使用线性拟合时,我们得到以下结果。
线性游戏
该模型不会像多项式模型那样高估较高的数据点。让我们用 20 条样条曲线进行多项式拟合。
用 20 条样条曲线 GAM。作者图片
在上述所有方法中,最后一个数字最符合数据。例如,如果我们想知道一条 1.7 厘米宽的鱼的重量,预测会更准确。对于使用 GAM 的多项式拟合,标准误差将更小。
结论
我们讨论了多项式和样条回归,并与 GAM 进行了比较。使用 GAM 时,无需手动指定结。这为拟合提供了更大的灵活性,因为它会自动用给定数量的样条拟合多项式。这基本上是过程的自动化,其中不需要选择中间点作为结。在实现回归模型时必须足够小心,应该比较不同的方法并调整超参数以获得最佳结果。
参考:
Python scikit 中的 fit()vs predict()vs fit _ predict()-learn
sklearn 中的 fit,predict 和 fit_predict 方法有什么区别
由 Kelly Sikkema 在 Unsplash 上拍摄的照片
scikit-learn (或俗称 sklearn )大概是 Python 中最强大、应用最广泛的机器学习库之一。它附带了一套全面的工具和现成的模型,从预处理实用程序到模型训练和模型评估实用程序。
许多 sklearn 对象,实现了三个具体的方法,即fit()
、predict()
和fit_predict()
。本质上,它们是 scikit-learn 及其 API 中应用的约定。在这篇文章中,我们将探讨每一个是如何工作的,以及何时使用其中的一个。
请注意,在本文中,我们将使用特定的示例来探索上述函数,但是这里解释的概念适用于实现这些方法的大多数(如果不是全部)对象。
在解释fit()
、predict()
和fit_predict()
背后的直觉之前,重要的是首先理解什么是 scikit-learn API 中的估计器。我们需要了解估计量的原因很简单,因为这样的对象实现了我们感兴趣的方法。
sci kit-learn 中的估计器是什么
在 scikit-learn 中,估计器是一个对象,它根据输入数据(即训练数据)拟合模型,并执行与新的、看不见的数据的属性相对应的特定计算。换句话说,估计器可以是回归器或分类器。
这个库带有基类[sklearn.base.BaseEstimator](https://scikit-learn.org/stable/modules/generated/sklearn.base.BaseEstimator.html#)
,所有的估算器都应该继承这个类。基类有两个方法,即get_params()
和set_params()
,分别用于获取和设置估计器的参数。注意估计器必须明确在构造器方法(即__init__
方法)中提供它们的所有参数。
fit()有什么作用
fit()
由每个估计器实现,它接受样本数据的输入(X
),对于监督模型,它还接受标签的参数(即目标数据y
)。或者,它还可以接受额外的样品属性,如重量等。
fit 方法通常负责许多操作。通常,他们应该首先清除已经存储在估计器上的任何属性,然后执行参数和数据验证。它们还负责从输入数据中估计属性,存储模型属性,并最终返回拟合的估计值。
现在作为一个例子,让我们考虑一个分类问题,我们需要训练一个 SVC 模型来识别手写图像。在下面的代码中,我们首先加载数据,然后将其分成训练集和测试集。然后我们实例化一个 SVC 分类器,最后调用fit()
使用输入的训练和数据来训练模型。
[**fit**](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html#sklearn.svm.SVC.fit)
( X , y , sample_weight=None ):根据给定的训练数据拟合 SVM 模型。X — 训练向量,其中 n_samples 是样本数,n_features 是特征数。
y — 目标值(分类中的类别标签,回归中的实数)。
样品重量— 每个样品的重量。重新调整每个样本的 C。较高的权重迫使分类器更加强调这些点。
现在我们已经成功地训练了我们的模型,我们现在可以访问拟合的参数,如下所示:
请注意,每个估计量可能有不同的参数,一旦模型拟合,您就可以访问这些参数。您可以在官方文档和正在使用的特定评估器的“属性”部分找到可以访问的参数。通常,拟合参数使用下划线_
作为后缀。特别是对于 SVC 分类器,您可以在文档的章节中找到可用的拟合参数。
predict()做什么
既然我们已经训练了我们的模型,下一步通常涉及对测试集的预测。要做到这一点,我们需要调用方法predict()
,该方法基本上使用fit()
学习到的参数,以便对新的、看不见的测试数据点进行预测。
本质上,predict()
将为每个测试实例执行一个预测,它通常只接受一个输入(X
)。对于分类器和回归器,预测值将与在训练集中看到的值处于相同的空间。在聚类估计中,预测值将是一个整数。所提供的测试实例的预测值将以数组或稀疏矩阵的输出形式返回。
注意,如果您试图在没有首先执行fit()
的情况下运行predict()
,您将收到一个[**exceptions.NotFittedError**](https://scikit-learn.org/stable/modules/generated/sklearn.exceptions.NotFittedError.html#sklearn.exceptions.NotFittedError)
,如下所示。
fit_predict()是做什么的
展望未来,fit_predict()
与无监督或直推式估值器更相关。本质上,这种方法将适合并执行对训练数据的预测,因此,在执行诸如聚类分析之类的操作时更合适。
[**fit_transform**](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html?highlight=k%20means#sklearn.cluster.KMeans.fit_transform)
( X ,y =无,sample _ weight =无 )
计算聚类,将 X 变换到聚类距离空间。相当于fit(X).transform(X)
,但实现更高效。
注意到
- scikit-learn 中的聚类估计器必须实现
fit_predict()
方法,但不是所有的估计器都这样做 - 传递给
fit_predict()
的参数与传递给fit()
的参数相同
结论
在本文中,我们讨论了 sklearn 中最常实现的三个函数的用途,即fit()
、predict()
和fit_predict()
。我们探讨了它们各自的功能和区别,以及在什么用例中应该使用其中的一个。
正如本文介绍中提到的,尽管我们使用了具体的例子来演示它们的行为,但本文中解释的概念几乎适用于 scikit-learn 中实现这些方法的所有估算器。
fit()
方法将使模型适合输入训练实例,而predict()
将根据在fit
期间学习到的参数对测试实例进行预测。另一方面,fit_predict()
与无监督学习更相关,在无监督学习中我们没有标记的输入。
一个非常相似的主题可能是比较由 scikit-learn 用于转换特性的转换器实现的fit()
、transform()
和fit_transform()
方法。如果你想了解更多,你可以阅读我下面的文章。
健身导航器
提高模型质量的 5 种方法
如果你只练腹肌,你不可能有很好的体形。相反,如果你和你的健身教练一起制定一个计划并努力执行,你可以更快地出现在海滩上,脸上带着微笑。
机器学习模型也是如此。每个人都知道你必须调整模型参数(例如神经网络权重)来获得一个好的模型。但这不是影响模型质量的唯一选择。我们将后退一步,探索其他改进方法。其中一些在某些机器学习问题中得到了广泛的应用,但其他一些仍然处于雷达之下。
下面是我对 J. Kukač ka,V. Golkov 和 D. Cremers 的一篇伟大论文的反思, 深度学习的正则化:一个分类学 (2017) [1]。
什么是最佳匹配?
当我们看下面的图片时,什么是“好的”适合就变得很清楚了:模型捕捉一般的数据模式,但是对给定数据不合理的模式不太敏感。
(1)最佳拟合。作者图片
模型复杂性,即模型参数的数量,控制模型学习复杂数据模式的能力。但是当你将一个简单的数据输入到一个复杂的模型中时,会导致过度拟合——模型试图利用它的“冗余”参数,最终“记忆”数据点。并且当模型对新的数据点做出推断/预测时,记忆通常是不好的。欠拟合发生在相反的情况下——当一个简单的模型被输入一个复杂的数据。这也是不好的,因为不足的模型不能捕捉复杂的数据模式。
当模型复杂性与数据复杂性平衡时,获得最佳拟合。实现平衡是一个挑战,因为模型学习训练数据样本中的模式,但最终目标是对新数据样本(即分布可能不同的测试数据)进行高质量的预测。但是正如我们在下面看到的,有很多方法可以达到这种平衡。
(2)训练-测试误差权衡。作者图片
实现最优/最佳匹配的指导原则称为结构风险最小化【2】。它控制模型复杂性(正则化)和拟合训练数据的质量(经验风险/误差)之间的权衡。风险这个词指的是我们可能要为预测不准确付出的抽象代价。
(3)结构风险最小化。作者图片
如何衡量契合度的好坏?
我们可以通过合计实际数据和模型预测之间的偏差来量化我们对拟合的感知。每个偏差,即误差代表特征空间中的距离,距离的定义取决于问题的上下文和领域。
(4)不同特征空间中的误差函数的例子。作者图片
我们在选择误差/损失函数时非常灵活。然而,在实践中,我们用来调整模型参数以最小化误差的优化算法存在局限性,通常它们只能对全局连续和可微分的损失函数起作用。
除了误差之外,我们可能想要通过针对不期望的模型结构的正则化/ 惩罚来说明我们对模型架构或参数的偏好。
将误差和罚值结合在一起,我们获得了对给定数据的模型性能的度量— 成本函数。它反映了模型对数据的拟合程度以及我们对模型本身的偏好。在训练阶段,我们的目标是最小化该函数,以获得更好的拟合。
(5)成本函数,一般形式。作者图片
下面你可以看到一个在许多回归问题中使用的流行成本函数:MSE 损失函数结合 L2 权重正则化。
(6)作为 MSE + L2 的成本。作者图片
在成本函数中导航
让我们考虑重新设计成本函数的不同选项,以便解决最佳拟合过程中的各种挑战。
(1)数据转换
数据转换有两个概念:保留数据表示(数据扩充)和不保留数据表示(特征工程)。在训练和测试期间,两者都可以应用于模型输入、内部参数和输出。
(7)数据转换。作者图片
从这个角度来看,Droupout 和批处理规范化等技术源自与数据预处理或对扩充输入的聚合预测相同的原理。
许多特征工程和数据扩充技术是特定于领域的,但是通过将一个领域的技术应用于另一个领域的问题也可以获得令人印象深刻的结果。例如,通过傅立叶或小波变换将音频信号转换为图像,然后应用为计算机视觉问题设计的卷积神经网络(CNN)。
(8)将问题域从信号处理转向图像处理。作者图片
论文中列出的最违反直觉的技术之一是向训练数据添加随机噪声 —矛盾的是,在噪声分布的某些条件下,它改善了模型质量并增加了其鲁棒性。
(9)输入噪声的平滑效果。图片由作者提供,基于论文“反向传播训练期间添加噪声对泛化性能的影响”[3]中的图片
(2)型号
你的幻想是模型原型/网络架构的唯一限制。此外,你可以创建一个元模型,通过不同的集成技术结合不同基础模型的预测:装袋,助推和堆叠。
通常模型是讨论的焦点,所以今天我们跳过它。我只是建议思考一下 T4 的《神经网络动物园》。
(3)损失函数(一个样本的误差)
如上所述,问题域意味着损失函数的选择。然而,即使使用领域不可知的损失函数,例如用于回归的 MSE 和用于分类的交叉熵,通常也可以实现足够的模型质量。
在不平衡数据的情况下,考虑影响类权重是有意义的——这也可以通过在数据变换级别(1)上的下采样/过采样来实现。
影响样本权重对于时间序列预测尤其重要——这是平滑数据异常或关注数据中最新模式的便捷方式。
(4)正则化项
正则项独立于目标,因此可以针对未标记的样本进行计算,而损失函数则不能。这种区别允许通过以半监督学习的方式组合标记和未标记的数据来提高模型的鲁棒性。
基于权重衰减的正则化术语是最流行的:L1,L2。
(11) L1,L2 正规化条款。作者图片
正则化的思想也应用于模型选择的信息标准。例如,在 Akaike 准则中,我们可以观察到模型参数数量的损失[4]。
(12)阿凯克准则。作者图片
(5)优化算法
优化算法本质上是搜索模型参数的工具,该模型参数在训练数据集上传递成本函数的最小值。
最基本的优化算法是梯度下降(GD) 。它基于这样的想法,一个函数的导数是一个指向该函数局部最大值的向量。因此,相反方向的步骤会导致局部最小值,这正是我们所希望的。
(13)梯度下降。作者图片
在经典的梯度下降法中,所有的训练样本都用于每次参数更新——我们通常有一条正确方向的路径,但是学习可能非常慢。相反,使用所有训练样本中的一个样本或子样本可以提高训练速度,但是对于最小化代价函数来说,我们会经历更多的颠簸。这种算法变异被称为随机梯度下降(SGD) 。
有很多方法可以升级一个基本的随机梯度下降优化器。其中一些在每个参数的基础上考虑梯度的一阶和二阶矩:自适应梯度算法 (AdaGrad)、均方根传播 (RMSProp)和 Adam 。
另一个有趣的高级方法是快照集成方法。它旨在利用成本函数的多个局部最小值而不是一个全局最小值——所获得的模型是具有对应于局部最小值(快照)的参数的模型的集合。快速&有效的局部最小值搜索是通过循环改变学习率来实现的:这里我们不是恒定的学习率,而是首先降低学习率以达到局部最小值,保存模型快照,然后显著提高学习率以跳出最小值并移动到下一个局部最小值,重复该过程。
正如我们在上面的方法中看到的,优化器的停止标准不是一个显而易见的话题。模型参数的初始化也是至关重要的,可以显著加快训练程序。
除了上述优化器之外,还有一类优化器将成本函数视为“黑盒”,并使用代理模型来近似它。当成本函数的梯度很难计算或不存在时,这很有用。这一类中最受欢迎的技术是贝叶斯优化 —它通过用高斯过程近似成本函数而得出的每个新样本来更新关于成本函数的先验信念【6】。
技术等效
值得注意的是,有时影响成本函数不同组成部分的方法是等价的。例如,小方差高斯噪声的注入是雅可比损失的近似。文[1]中还有很多例子。
结论
通常,我们关注可以提高模型质量的特定组件,例如模型权重。但是通常当你解决一个真正的问题时,就没有这样的限制了。成本函数只是一种工具,帮助我们将目标传达给计算机/优化算法。只要它 1)能帮助我们更好地概括数据模式,2)能被输入到优化算法中,我们就有能力操纵它的所有组件。所以,下次当你在长时间的模型训练后感到停滞不前时——检查一下其他能给你带来质量提升的选项。
参考
[1]扬·库卡卡,弗拉基米尔·戈尔科夫和丹尼尔·克雷莫斯,深度学习的正规化:分类学 (2017)
[2]谷歌,机器学习速成班,正规化
[3]郭忠·安(1996),在反向传播训练期间增加噪声对泛化性能的影响
[4]罗伯·J·海曼,乔治·阿萨纳索普洛斯,预测:原理与实践
[5]黄,g .,李,y .,普莱斯,g .,刘,z .,霍普克罗夫特,J. E .,&温伯格,K. Q .,《快照集:训练 1,免费获得 M》(2017 年)
[6]马丁·克拉瑟,贝叶斯优化 (2018)
特别感谢 Stepan Zaretsky,他早些时候向我介绍了这篇论文[1],甚至验证了一些关于模型受益于噪声注入的结果。
R 中拟合点过程模型
理解和实现对数高斯考克斯过程
图片由来自 unsplash 的米哈里·科尔斯拍摄
在之前的帖子中,我们了解了泊松点过程模型以及如何将其融入Stan
& spatstat
。在泊松点过程模型中,我们假设每个点相互独立。由于自然喜欢使我们的生活复杂化,这一假设很少得到满足,我们需要考虑我们的观察之间的任何依赖性,以使我们的统计模型正确。
在查看对数高斯考克斯过程之前,先看一下考克斯过程在概念上是有见地的。
加载库
要重现本教程,您将需要这些库:
考克斯过程
在非均匀泊松过程的情况下(我们在第一部分描述过),强度函数在空间上变化,但由确定性强度函数给出:
作者图片
在 Cox 过程的情况下,强度测量可以是非负随机变量或随机场的实现:
作者图片
u(s)是随机函数(即一些噪声)。这解释了为什么考克斯过程也被称为双随机泊松过程。
为了生成 Cox 过程的实现,我们需要生成底层随机函数λ(s)的实现,它也被称为驱动强度。
下面的函数genDat_cox
将产生一个 Cox 过程的代。你可以将它与第一部分的genDat_ppp
进行比较,我们基本上只是添加了一些噪声或一个随机场。
我们为可复制的结果和参数值设置了一个随机种子。注意,这次我们还指定了噪声的参数。
作者提供的图片
现在让我们在 Stan 中拟合模型,看看是否可以恢复我们的参数。下面的 Stan 代码并不比拟合非齐次泊松点过程的代码复杂多少,我们只需要增加一个参数σn 来估计噪声。我们假设噪声正态分布,均值为 0,标准差为σn:噪声=N(0,σn)
注意,我们需要接受截距为 b0 + mean_noise,误差为 0。随机效应的平均值是不可能的。这就是所谓的不可识别性问题(详见 此链接 )。
我们现在可以拟合模型:
从输出中我们可以看到,模型成功地恢复了我们之前指定的参数。
作者图片
注意,如前所述,在模型输出中,β0=截距+噪声,这与我们指定的参数值一致:β0=2,噪声=1
由于我们已经编写了一些代码在generated quantities
块中进行预测,我们可以绘制预测的强度,并将其与 Cox 过程的实际强度进行比较。
作者图片
作者图片
作者图片
当然,由于模型的随机性,我们不会得到与真实模式完全相同的模式。
对数高斯考克斯过程
让我们增加复杂性。我们定义对数高斯 Cox 过程(LGCP)是一种双重随机结构,由泊松点过程组成,其随机对数强度由高斯随机场给出。这意味着这一次,来自前述 Cox 过程的非负随机变量是一个高斯随机场(或 GRF)。这听起来比现实中更可怕。
当我们模拟 cox 过程时,我们首先在研究区域创建了一些随机噪声,这是我们的随机场:
作者图片
噪声值完全随机分布。在高斯随机场中,噪声值不是随机分布的,而是遵循二元高斯分布。这意味着观察值是相互关联的。实际上,这意味着这个随机变量将使观测值聚集在空间的某个区域。将会有“热点”和“冷点”,在“热点”处,GRF 的值将会很高并且将会“吸引”观测。
我们可以通过平滑我之前定义的噪声来创建一个 GRF:
作者图片
我们现在可以清楚地想象“热点”和“冷点”。
如果不考虑 GRF,我们就会有空间相关性(如果你在二维空间工作)并且观察结果不是相互独立的,这会扰乱我们的统计模型。通常这会导致较低的可信/置信区间,并使我们对结果过于自信。
直观上,我们可以认为,如果由于空间相关性,彼此靠近的观测值更加相似,那么我们需要定义一个函数,使得空间相关性随着距离而减小。为此,我们可以使用诸如指数协方差函数、指数二次协方差函数或 Matèrn 协方差函数之类的函数。我们将在下一节中更详细地了解这一点。
我们可以使用spatstat
包中的函数rLGCP
来模拟 GRF 的实现。我们在下面的genDat_lgcp
函数中使用了它:
我们定义了参数并模拟了对数高斯 Cox 过程。
作者图片
现在是做推论的时候了,说明点与点之间的空间相关性!
指数协方差函数
我们首先通过假设两点之间的协方差遵循指数协方差结构来构建模型。这意味着两点之间的相关性呈指数下降:
作者图片
- σ是相关性的方差
- d 是两点之间的距离
- ρ是相关性下降的速率。如果它很大,则意味着相关性迅速降低。
在 Stan 中,我们编写了将说明function
块中高斯随机场的函数。看一看吧,内容很丰富。
请注意,您可以随意调整相关函数,因此,如果您认为假设两点之间的相关性呈指数下降是错误的,您可以更改第 10 行中指定的公式:
这是完整模型的样子:
为了拟合 Stan 中的模型,我们首先需要计算点之间的距离矩阵。这将是来自 GP 函数的matrix x
参数。因为我们有网格单元而不是点,所以我们计算网格单元的质心的距离。
我们现在已经拥有了符合 Stan 模型的所有元素。注意,我给stan
函数添加了一些参数。我将adapt_delta
设置为 0.999,将max_treedepth
设置为 13。虽然我不知道它们目的的具体细节,但它们有助于模型正确收敛。
模型需要一些时间来运行(这是一个非常小的数据集!)但是我们能够恢复所有参数。为了了解协方差降低的距离,我们可以使用参数值来绘制曲线图:
作者图片
我们可以看到,在距离接近 5 个单位时,相关性变为零。
指数二次协方差函数
而在第一个模型中,我们有更多的灵活性,斯坦有一个预定义的相关函数,使编码更简单。cov_exp_quad
使用指数二次协方差函数,这是另一个非常常见的协方差函数,其中:
作者图片
更详细的解释见标准函数参考。
安装 LGCP 的快速替代方案🚀
有可能更有效地(或至少更快速地)拟合对数-高斯 Cox 过程。对数高斯 Cox 过程可能特别长,因为估计高斯场需要一些时间。一些方法寻求近似高斯场,减少计算时间。如果你对此感兴趣,可以看看 Stan 中可能用到的谱近似和 R-INLA 使用的随机偏微分方程。
喜欢这个故事吗?
如果你对空间统计、深度学习和更广泛的数据科学感兴趣,你可以在我的 Twitter 或我的 Linkedin 上关注我!
Python 中的五个高级绘图— Matplotlib
西蒙·李在 Unsplash 上的照片
带示例的交互式 3d 绘图
由于显而易见的原因,数据可视化可能是数据科学中使用最广泛的特性。可视化是呈现和理解数据的最佳方式。因此,拥有大量可视化工具是一个好主意。因为不同的视觉化在不同的情况下是合适的。在本文中,我将分享 Matplotlib 中五个 3d 可视化的一些代码。
我假设,你知道 Matplotlib 中的 2d 绘图。所以,我就不去过多讨论了。本文将简单演示如何制作这五个情节。
我将在本文中演示五个 3d 图:
- 散点图
- 等值线图表
- 三面图
- 表面图
- 条形图
我在这篇文章中使用了来自 Kaggle 的数据集。
资料组
如果你想自己运行这段代码,请随意从这个链接下载数据集。这是一个开放的数据集,这里提到的是。
首先导入必要的包和数据集:
import pandas as pd
import numpy as np
from mpl_toolkits import mplot3d
import matplotlib.pyplot as pltdf = pd.read_csv("auto_clean.csv")
数据集相当大。所以我不会在这里展示任何截图。以下是该数据集的列:
df.columns
输出:
Index(['symboling', 'normalized-losses', 'make', 'aspiration', 'num-of-doors','body-style', 'drive-wheels', 'engine-location', 'wheel-base', 'length', 'width', 'height', 'curb-weight', 'engine-type', 'num-of-cylinders', 'engine-size', 'fuel-system', 'bore', 'stroke', 'compression-ratio', 'horsepower', 'peak-rpm', 'city-mpg', 'highway-mpg', 'price', 'city-L/100km', 'horsepower-binned', 'diesel', 'gas'] ,dtype='object')
让我们转到绘图部分。
散点图
散点图非常简单明了。我假设你知道二维散点图。要制作一个 3d 散点图,我们只需要使用' scatter3D '函数并传递 x、y 和 z 值。我选择使用 x、y 和 z 值的高度、宽度和长度。
为了添加更多的信息,也为了添加一些样式,我将把价格作为大小参数传递。我觉得散点图有不同大小的气泡和不同的颜色看起来很好看。同时,尺寸包含了更多的信息。
因此,泡沫越大,价格越高。同样的图将给出价格如何随高度、宽度和长度而变化的想法。颜色也随着峰值转速而变化。
%matplotlib notebook
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection="3d")
ax.scatter3D(df['length'], df['width'], df['height'],
c = df['peak-rpm'], s = df['price']/50, alpha = 0.4)
ax.set_xlabel("Length")
ax.set_ylabel("Width")
ax.set_zlabel("Height")
ax.set_title("Relationship between height, weight, and length")
plt.show()
作者图片
该图是交互式的,有助于更好地理解数据:
作者制作的动画
条形图
条形图总是有用的。但是当它是 3D 条形图时,可能会更有用。在这里,我将根据车身风格和峰值转速来标出价格。为此,需要做一些数据准备。首先,体型是一个范畴变量。body_style 列的值如下:
df['body-style'].unique()
输出:
array(['convertible', 'hatchback', 'sedan', 'wagon', 'hardtop'],
dtype=object)
这些字符串需要替换为数值:
df['body_style1'] = df['body-style'].replace({"convertible": 1,
"hatchback": 2,
"sedan": 3,
"wagon": 4,
"hardtop": 5})
现在,我将找到每种车身类型的平均峰值转速和价格。
gr = df.groupby("body_style1")['peak-rpm', 'price'].agg('mean')
输出:
对于 3d 条形图,我们显然需要将 x、y 和 z 值传递给 bar3d 函数,如您所料。但它也要求 dx,dy 和 dz。
首先,考虑将要放置横条的 2d 平面,这里我们只能使用 x 和 y 值,z 值为零。因此,我们将在 x 轴上使用 body_style1,在 y 轴上使用 peak-rpm,如前所述,在 2d 平面上 z 值为零。
接下来,我们应该指定条形的大小。我在 x 轴上使用宽度 0 .3,在 y 轴上使用宽度 30,高度将是价格列的值。这意味着,
dx = 0.3
dy = 30
dz = gr['价格']
下面是条形图的代码片段:
%matplotlib notebook
x = gr.index
y = gr['peak-rpm']
z = [0]*5colors = ["b", "g", "crimson", 'r', 'pink']dx = 0.3 * np.ones_like(z)
dy = [30]*5
dz = gr['price']fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection="3d")
ax.set_xticklabels(['convertible', 'hatchback', 'sedan', 'wagon', 'hardtop'])
ax.set_xlabel("Body Style", labelpad = 7)
ax.set_yticks(np.linspace(5000, 5250, 6))ax.set_ylabel("Peak Rpm", labelpad=10)ax.set_zlabel("Price")
ax.set_zticks(np.linspace(7000, 22250, 6))
ax.set_title("Change of Price with Body_style and Peak RPM")ax.bar3d(x, y, z, dx, dy, dz)
作者图片
以下是条形图的完整视图:
作者制作的动画
这里是条形图!
表面图
对于这种类型的绘图,一维 x 和 y 值不起作用。因此,我们需要使用“meshgrid”函数从两个一维数组中生成一个矩形网格。
该图显示了 3d 设置中两个变量之间的关系。
我选择看这个图的长宽关系。以下是该表面图的代码:
def z_function(x, y):
return np.sin(np.sqrt(x**2 + y**2))plt.figure(figsize=(10, 10))
ax = plt.axes(projection="3d")x = df['length']
y = df['width']X, Y = np.meshgrid(x, y)
Z = z_function(X, Y)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
cmap='winter', edgecolor='none')
ax.set_xlabel("Length")
ax.set_ylabel("Width")
ax.set_title("Peak RPM vs City-MPG")
ax.view_init(65, 30)
作者图片
这是表面图的完整视图
作者制作的动画
等值线图表
也许你已经知道二维等高线图。在这里,我用 3d 等高线图展示了峰值转速和城市英里数之间的关系。
在这个例子中,我对 z 值使用了 sin 函数。你可以用余弦函数试试。
以下是代码片段:
%matplotlib notebook
def z_function(x, y):
return np.sin(np.sqrt(x**2 + y**2))
plt.figure(figsize=(10, 10))
ax = plt.axes(projection="3d")
x = df['peak-rpm']
y = df['city-mpg']
X, Y = np.meshgrid(x, y)Z = z_function(X, Y)
ax.contour3D(X, Y, Z, rstride=1, cstride=1,
cmap='binary', edgecolor='none')
ax.set_xlabel("Peak RPM")
ax.set_ylabel("City-MPG")
ax.set_title("Peak RPM vs City-MPG")
ax.view_init(60, 35)
plt.show()
作者图片
这是这个等高线图的完整视图
作者制作的动画
请尝试对 z 函数使用余弦,并查看使用相同数据时余弦等值线的外观。
三面图
让我们看看三冲浪图是什么样子的。我们不需要网格网格的三冲浪图。简单的一维数据适合 x 和 y 方向。
这是代码。
%matplotlib notebookplt.figure(figsize=(8, 8))
ax = plt.axes(projection="3d")x = df['peak-rpm']
y = df['city-mpg']
z = z_function(x, y)
ax.plot_trisurf(x, y, z,
cmap='viridis', edgecolor='none');
ax.set_xlabel("Peak RPM")
ax.set_ylabel("City-MPG")
ax.set_title("Peak RPM vs City-MPG")
ax.view_init(60, 25)
plt.show()
作者图片
这是整个情节的轮廓
作者制作的动画
结论
这是我想在这篇文章中分享的五个情节。我希望您将在自己的项目中使用它们。
欢迎随时关注我的推特(Twitter)和我的新 T2 YouTube 频道(T3)。
更多阅读
每个数据科学家都应该避免的五个坏习惯
以及如何预防!
玛利亚·特内娃在 Unsplash 上拍摄的照片
没有人喜欢坏苹果。
也没有人喜欢坏习惯。
在我的数据科学之旅中,我和其他几个刚起步的人一起学习和成长。回想起来,我意识到我们许多人都有一些常见的坏习惯。
所以,我想和你分享这五个坏习惯,这样你就可以防止自己陷入其中。
让我们开始吧!
1)没有完全理解你试图解决的业务问题。
这是大多数数据科学家(包括我自己)在开始时都会犯的一个非常普遍的问题。为什么?通常,当人们了解数据科学并开始他们的第一个数据科学项目时,他们试图解决的问题 1)很简单,2)很简单(即训练营/教程)。
例如,如果你考虑 Kaggle 比赛,主持人清楚地概述了问题是什么,什么数据是可用的,以及要优化什么指标。不幸的是,这完全歪曲了现实。
在现实世界中,更有可能的情况是,您会收到模糊的指示,尤其是如果您正在与一个不太懂数据科学的团队一起工作。举个例子,你可能会被告知“量化营销活动”或“预测欺诈交易”,但没有更多细节。
如何预防
在直接跳到数据之前,花一些时间收集信息。在开始任何类型的数据科学项目之前,确保你能回答这些问题:
- 我试图解决什么业务问题?
- 这是什么数据科学问题?例如,二元分类与多级分类
- 如何定义成功,如何衡量成功?
- 谁是领域专家?谁是利益相关者?
- 这种模式将如何使用?此外,它将如何在业务流程或产品中实现?
通过回答这些问题,你会对你想要达到的目标有一个更好的理解,并且你不太可能不得不退回和重复某些步骤。
2)急于完成你的数据科学项目。
这与第一点有关,但也适用于机器学习生命周期中的所有其他阶段。具体来说,有两个阶段是许多数据科学家倾向于匆忙完成的:数据探索和模型验证。
数据探索
与第一点类似,许多数据科学家也倾向于忽略这个阶段。回到我的 Kaggle 示例,竞赛主持人非常清楚地说明了每个功能代表什么,您不必担心数据是如何生成的,或者有什么数据——因此在这种情况下,不完全需要“数据探索”的概念。
然而,在现实中,您将不得不花费更多的时间来探索哪些数据是可用的,数据是如何生成和转换的,以及数据的一般特征是什么。
需要回答的重要问题包括:
- 有哪些特征变量可用,目标变量是什么?
- 每个特征代表什么?
- 数据是如何产生的?管道/扯皮流程是怎样的?
- 所选数据的特征是什么(观察值数量、变量数量、时间尺度、数据类型等)。)
- 是否存在缺失值?怎么处理他们?
- 有没有异常值?他们为什么在那里?
模型验证
就像你在软件工程中执行几个测试一样(单元、端到端、集成等等。),模型验证允许你测试你的机器学习模型。因此,您希望确保您正在彻底地测试(验证)它,并且您的测试(验证)是健壮的。
以下是关于模型验证以及如何改进模型验证的几点:
- 如果您只是将数据集拆分为定型集和测试集,那么实际上应该将数据集拆分为定型集、验证集和测试集。验证集的目的是让您可以调整超参数,将测试集留给最终测试。首席决策科学家@ Google 的 Cassie Kozyrkov 在上面有一个惊人的视频 这里 。
- 更进一步,您可以使用 k-Fold 交叉验证等技术来进一步最小化采样偏差,并最终防止训练集过度拟合。
- 除了交叉验证之外,您还应该花一些时间用您自己的输入手动测试模型。
具体来说,我喜欢做的就是用 Gradio 快速为我的机器学习模型创建一个 web UI。我发现 Gradio 在验证我的模型时非常有用,原因如下:
- 它允许我交互式地测试模型的不同输入。
- 它允许我从领域用户和领域专家(他们可能不是编码人员)那里得到反馈
- 它需要 3 行代码来实现,并且可以通过公共链接轻松分发。
像这样使用图书馆的最大好处是,它也是给你的同事留下深刻印象的好方法😏。我向你保证,用它来部署你的模型,比把你那破烂的 Jupyter 笔记本送过去好 100 倍!
3)试图用最复杂的模型来解决你的问题。
如果你看过我之前的文章,想成为数据科学家,不要从机器学习开始 ,你可能还记得我的观点,“机器学习不是每个数据科学家问题的答案。”
这一点与此相似,但有进一步的发展。如果你可以在三周内建立一个准确率为 95%的模型,而在三个月内建立一个准确率为 99%的模型,你认为大多数企业会选择哪个?
一般来说,他们更有可能选择第一个选项。为什么?因为模型性能不是构建模型时的唯一因素。还有一些因素,如实现时间、易解释性和可维护性等。
因此,如果您可以用 if/else 语句构建一个简单的基于规则的模型来解决手头的问题,为什么还要为一个 10 层的神经网络费心呢?
如何预防
在大多数情况下,最好构建最简单的模型,并确定构建下一个最佳替代方案是否超过成本。要给出一个简单的框架,请依次问自己以下问题:
- 我的问题能用简单的 Python 脚本或 SQL 查询解决吗?
- 我的问题可以用决策树(if/else 语句)解决吗?
- 我的问题可以用简单的机器学习模型来解决吗,比如线性回归或随机森林?
如果这三个问题的答案都是否定的,那么你可以考虑你的 10 层神经网络😉。
4)试着全靠自己。
作为一名数据科学家,最大的好处之一就是你被赋予了很大的自主权。但是,如果你不愿意向他人寻求建议、帮助和反馈,这很容易导致失败。
当理解业务问题时,你必须与利益相关者交谈以理解他们的需求。在探索数据时,您可能需要与领域专家交流,以了解特定的特性以及它们是如何被吸收的。当验证你的模型时,你最好想从别人那里得到反馈。
如何预防
这里没有神奇的解决方法,但是要学会接受别人的想法、观点和知识。你对面临的问题了解得越多,你就越有可能成功解决它!
5)没有有效地传达你的方法和见解
这一点包含两个更小的点。
对于数据科学家来说,很难用普通人能够理解的方式来翻译他们的知识和见解。也就是说,您必须能够以非技术人员能够理解的方式交流技术术语和建模技术。如果你花时间建立了一个伟大的模型,你应该多花一点时间来有效地沟通,这样人们才能认可你的努力!
第二,正如我前面提到的,数据科学家一般都有很大的独立性。然而,您必须不断地与其他利益相关者沟通,让他们了解您的思维过程、您对模型的任何假设,并获得反馈。否则,您可能最终得到一个不能解决当前问题的模型。
如何预防
花点时间把你的思维过程分解成更容易理解的形式,比如一篇文章、一张幻灯片或一个网络界面,这与我之前的观点相关。使用像 Gradio 这样的库可以帮助提高模型的可解释性,并从非技术利益相关者那里获得反馈。
感谢阅读!
这是我的另一篇固执己见的文章,所以你可以随意从中得到你想要的,但我希望你会发现这很有见地。想要直接跳到有趣的东西,即建模,是如此诱人,但请记住,这只是数据科学家日常工作的一小部分!
一如既往,我祝你学习一切顺利:)
不确定接下来该读什么?我为你挑选了另一篇文章:
***
链接到 Gradio:
特伦斯·申
R 中 dplyr 入门的 5 个基本命令
Dplyr 相当于 Python 中的 Pandas 库,可以轻松地进行数据探索和操作
杰夫·西普曼在 Unsplash 上的照片
我开始了我的数据科学之旅,学习如何使用 Pandas 库,事实上,它有着令人喜爱的一切-它易于使用,简单明了,并且具有几乎任何涉及操作和探索数据框的任务的功能。
见鬼,我甚至在 YouTube 上制作了一个完整的视频系列,教其他人如何使用熊猫。随便看看(不要脸的塞)!
然而,最近,我发现自己在 R 上花了越来越多的时间,主要是因为我在准备精算考试,但我也很好奇,想了解人们在 R 中使用的 Pandas 等效工具。
现在,如果您正在寻找 Python 与 R 的辩论,那么这篇文章不是您要找的。就我个人而言,我认为你可以添加到工具箱中的工具越多,你就变得越好,或者用数据科学的术语来说,你知道的语言或库越多,作为一名数据科学家,你就变得越灵活和有效。
此外,在现实世界中,并不总是由你来决定你想为一个特定的项目使用哪种语言,所以扩展你的知识和技能真的没有坏处。
Dplyr 功能
正如我提到的,对于那些已经熟悉熊猫的人来说,dplyr 在功能上非常相似。有人可能会说 dplyr 编写和解释起来更直观,尤其是在使用链接语法时,这一点我们将在后面讨论。
如果您完全是新手,不要担心,因为在本文中,我将分享 5 个基本命令来帮助您开始使用 dplyr,这些命令包括:
- 过滤器
- 挑选
- 安排
- 使突变
- 概括
除了这些命令,我还将演示 base R 方法来获得相同的结果,以突出 dplyr 的可读性。
事不宜迟,我们开始吧!
导入 dplyr 库和饮料数据集
如果您的计算机上还没有安装 dplyr,您可以通过以下命令进行安装。
install.packages("dplyr")
一旦你安装了这个库,我们现在就可以导入 dplyr 以及我们将在本教程中使用的数据集,按国家分类的饮料数据集。
library(dplyr)
drinks = read.csv("http://bit.ly/drinksbycountry")
head(drinks)
该数据集包含世界上 193 个国家的酒精消费信息。
命令 1:过滤
filter 命令允许我们保留符合某些指定标准的行,通常是 and/or。
和标准
假设我们想查看没有啤酒供应的亚洲国家。
# Base R approach
drinks[drinks$continent == "Asia" & drinks$beer_servings == 0, ]# Dplyr approach
filter(drinks, continent == "Asia", beer_servings = 0)
或标准
假设现在我们想查看没有烈酒供应或没有葡萄酒供应的国家。
# Base R approach
drinks[drinks$spirit_servings == 0 | drinks$wine_servings == 0, ]# Dplyr approach
filter(drinks, spirit_servings == 0 | wine_servings == 0)
命令 2:选择
接下来,我们有 select 命令,它允许我们按名称选择列。
假设,我们想查看国家的前 6 行和纯酒精的总升数列。
# Base R approach
head(drinks[, c("country", "total_litres_of_pure_alcohol")])# Dplyr approach
head(select(drinks, country, total_litres_of_pure_alcohol))
为了使 select 命令更加健壮,我们还使用了以下内容来按名称匹配列:
- 开始于
- 以...结尾
- 比赛
- 包含
这里,我想选择包含单词 servings 的列。
head(select(drinks, contains("servings")))
额外好处:通过%>%链接多个操作
我之前谈到了 R 相对于 Python 的可读性优势。这个优势很大程度上归功于能够通过%>% 语法将多个操作链接在一起。
链接方法不是将不同的操作嵌套在一行代码中,这有时会变得混乱和难以阅读,而是提供了一种更直观的方法来编写和解释操作。
思考这个过程的一个好方法是想象你在一个工厂,每个操作就像一个工人,他是这个庞大制造过程的一部分,负责一个非常具体的任务。一旦他完成了他的任务,他就把它传递给下一个工人去执行他们的任务,如此等等,直到最终产品被交付。
还值得分享一下%>%的 Windows 快捷键,那就是 Ctrl+Shift+M。
现在,假设我们希望选择国家和纯酒精总升数列,并筛选纯酒精量超过 12 升的行。
# Nesting method
filter(select(drinks, country, total_litres_of_pure_alcohol), total_litres_of_pure_alcohol > 12)# Chaining method
drinks %>%
select(country, total_litres_of_pure_alcohol) %>%
filter(total_litres_of_pure_alcohol > 12)
正如我们所看到的,链接显著提高了代码的可读性,尤其是当有许多命令在运行时。
链接也可以用来替换 dplyr 之外的 R 命令中的嵌套。例如,假设我们要计算两组数字之间的均方根误差,精确到小数点后五位。
# Create two vectors
set.seed(42)
x = runif(10); y = runif(10)# Nesting method
round(sqrt(mean((x-y)^2)), 5)# Chain method
(x-y)^2 %>% mean() %>% sqrt() %>% round(5)
在这里,你应该得到 0.36466 的 RMSE。
命令 3:排列
接下来,我们有一个不言自明的命令。它有助于按升序或降序排列行。
假设我们想在每个国家从最低到最高点啤酒。
# Base R approach
drinks[order(drinks$beer_servings), c("country", "beer_servings")]# Dplyr approach
drinks %>%
select(country, beer_servings) %>%
arrange(beer_servings)
或者,对于降序,我们需要使用 desc。
drinks %>%
select(country, beer_servings) %>%
arrange(desc(beer_servings))
命令 4:变异
命令 4 是 mutate,它允许我们创建新的变量,这些变量是数据框中现有变量的函数。
假设我们想添加一个新的变量,叫做平均酒精,它就是啤酒、烈酒和葡萄酒之间的平均份量。
# Base R approach
drinks$avg_alcohol = round((drinks$beer_servings + drinks$spirit_servings + drinks$wine_servings) / 3)
head(drinks[, c("country", "beer_servings", "spirit_servings", "wine_servings", "avg_alcohol")])# Dplyr approach
drinks %>% select(country, beer_servings, spirit_servings, wine_servings) %>% mutate(avg_alcohol = round((beer_servings + spirit_servings + wine_servings) / 3)) %>% head()
命令 5:总结
最后但同样重要的是,summarise 命令使用聚合函数将变量缩减为值。聚合函数的一些示例包括最小值、最大值、中值、众数和平均值。
在这里,让我们看一个例子,我们想计算平均葡萄酒服务的大洲。
# Base R approach
aggregate(wine_servings ~ continent, drinks, mean)# Dplyr approach
drinks %>%
group_by(continent) %>%
summarise(avg_wine = mean(wine_servings, na.rm = TRUE))
结论
总之,在本文中,我们学习了 dplyr 库的 5 个基本命令,这些命令使我们能够探索和转换数据帧。这 5 个命令是:
- 过滤器
- 挑选
- 安排
- 使突变
- 概括
此外,我们还看到了如何通过%>%操作符部署链接方法,以使我们的代码更易于编写和阅读。
我希望你喜欢这篇文章,并从中获得一些有用的东西。请随意查看我关于如何使用 r 的其他教程文章。
https://medium.com/swlh/customer-segmentation-using-k-means-clustering-in-r-a74d512a4cfa
保重,继续学习!
稳定数据处理的五个最佳实践
在设置 ETL 或 ELT 这样的过程时,您应该记住什么
蒂姆·皮特森在 Unsplash 上拍摄的照片
以下五点是实现 ELT 或 ETL 等数据过程的基础。
防止错误
如果失败,应该执行回滚—类似于 SQL:如果作业因出错而中止,那么所有更改都应该回滚。否则,只有 X%的事务被传输,一部分丢失。你很难找到丢失的数据是什么。
公平处理时间
一个作业处理 X 个数据行需要多长时间?这为该过程提供了重要的见解。流程运行的频率和时间?我可以向我的部门保证哪些数据的真实性?当数据必须重新加载时会发生什么?等。
数据质量测量作业
我的源系统和目标系统是否兼容?如何确定所有数据都已传输完毕?在这里,我建议建立一个监控。衡量数据质量和快速检测错误总是一个好主意,否则可能会导致消费者缺乏信任。在这里找到一些灵感【1】。
交易安全
当在您的流程中使用数据库复制软件(例如 Amazon DMS)而不是系统 A 和 B 之间的直接连接时,您可能会遇到麻烦:我曾经有一个复制作业同时从表 A 和表 B 加载数据。两者都由 ETL 过程进一步处理,但是如果来自表 B 的数据集由于高延迟而不可用,并且来自表 A 的数据集被处理,则来自表 B 的信息丢失。在此,我还建议在此过程中监控或分配过多的附加成分。
考虑对其他系统的依赖性
对于源系统,必须考虑各种情况:
可用性:源系统什么时候可用?考虑维护周期、停机时间等。
高数据负载:目标系统不得从源系统接收任何不必要的更改(CDC),例如在高峰时间。因此,按照上述观点,例如,数据传输可以在例如夜间的批处理作业中进行。
其他系统的不必要行为:如上所述,数据库复制服务可能会破坏您的 ETL 过程,但也会出现其他问题,例如重复和不一致的数据。在这里,了解源系统及其缺陷是很重要的。
结论
对我来说,这是建立稳定和安全的数据流程的五个最重要的组成部分。你应该永远记住,数据质量是一个非常重要的话题。否则,您可能会缺乏用户和业务部门的信任。
资料来源和进一步阅读
[1]克里斯蒂安·劳尔,如何提高你的数据仓库质量 (2020)
编写干净专业的 SQL 代码的五个最佳实践
用这五个技巧提升你的 SQL 代码!
介绍
SQL 是数据世界中的通用语言。如果你是数据分析师、数据科学家、数据工程师、数据架构师等。,你需要写好的 SQL 代码。
学习如何编写基本的 SQL 查询并不难,但是学习如何编写好的 SQL 代码却是另一回事。编写好的 SQL 代码并不困难,但是需要学习一些规则。
如果您精通 Python 或另一种编码语言,这些规则中的一些可能对您来说很熟悉,这是因为它们非常具有可移植性!
因此,我将与您分享编写更干净、更好的 SQL 查询的五个技巧。让我们深入了解一下:
1.程序设计式样
如果你认为你的编程风格对于 SQL 来说是微不足道的,请再想想。您编码的风格对于可解释性和最小化错误是至关重要的。
让我给你一个简单的例子——下面两个代码块中哪一个更易读?
SELECT name,height,weight,age,gender,CASE WHEN age<18 THEN "child" ELSE "adult" END AS childOrAdult,salary
FROM People LEFT JOIN Income USING (name)
WHERE height<=200 and age<=65
或者
SELECT name
, height
, weight
, age
, gender
, CASE WHEN age < 18 THEN "child"
ELSE "adult"
END AS childOrAdult
, salary
FROM People
LEFT JOIN Income USING (name)
WHERE height <= 200
AND age <= 65
很明显,第二个更容易阅读,这完全归功于它的编程风格!编程风格有几个组成部分,但我们将重点放在缩进和空格上。
缩进/对齐
第二个代码块更易读的主要原因是因为它的缩进和垂直对齐。请注意 SELECT 子句中的所有列名是如何对齐的,WHERE 子句中的条件是如何对齐的,CASE 语句中的条件是如何对齐的。
你不一定要完全遵循这种方式,但是你应该尽可能地使用缩进并对齐你的语句。
间隔
空格是指您在代码中使用的空白。例如,代替…
WHERE height<=200 AND age<=65
考虑使用空白以使其更加易读:
WHERE height <= 200 AND age <= 65
最重要的是,你要确保你的编程风格在你的代码中是一致的。还有其他需要考虑的事情,比如命名约定和注释,我们将在本文后面讨论。
2.通过公共表表达式模块化代码
使用公共表表达式(cte)是模块化和分解代码的好方法,就像你将一篇文章分解成几个段落一样。
如果您想更深入地了解 cte,可以查看本文,但是如果您曾经想要查询一个查询,这就是 cte 发挥作用的时候——cte 本质上创建一个临时表。
考虑以下在 where 子句中带有子查询的查询。
SELECT name
, salary
FROM People
WHERE name in (SELECT DISTINCT name
FROM population
WHERE country = "Canada"
AND city = "Toronto")
AND salary >= (SELECT AVG(salary)
FROM salaries
WHERE gender = "Female")
这似乎不难理解,但是如果在子查询中有许多子查询呢?这就是 cte 发挥作用的地方。
with toronto_ppl as (
SELECT DISTINCT name
FROM population
WHERE country = "Canada"
AND city = "Toronto"
), avg_female_salary as (
SELECT AVG(salary) as avgSalary
FROM salaries
WHERE gender = "Female"
)SELECT name
, salary
FROM People
WHERE name in (SELECT DISTINCT FROM toronto_ppl)
AND salary >= (SELECT avgSalary FROM avg_female_salary)
现在很明显,WHERE 子句正在过滤多伦多的名称。如果你注意到了,CTE 是有用的,因为你可以把你的代码分解成更小的块,但是它们也是有用的,因为它允许你给每个 CTE 分配一个变量名(例如 toronto_ppl 和 avg_female_salary)
注意:编程风格也适用于 cte!
说到命名约定,这引出了我的下一个观点:
3.变量命名约定
命名约定有两部分需要考虑:使用的字母大小写类型和变量的描述性。
字母大小写
我个人喜欢用 snake_case 命名 cte,用 camelCase 命名列名。你可以选择你喜欢的方式来设计你的变量,但是要确保你是一致的。
这里有一个例子:
with short_people as (
SELECT firstName
FROM people
WHERE height < 165
)SELECT * FROM short_people
注意我是如何用 snake_case 表示 CTE (short_people ),用 camelCase 表示名字的。
描述性名称
理想情况下,您希望您的变量名描述它们所代表的内容。考虑我之前的例子:
with toronto_ppl as (
SELECT DISTINCT name
FROM population
WHERE country = "Canada"
AND city = "Toronto"
), avg_female_salary as (
SELECT AVG(salary) as avgSalary
FROM salaries
WHERE gender = "Female"
)SELECT name
, salary
FROM People
WHERE name in (SELECT DISTINCT FROM toronto_ppl)
AND salary >= (SELECT avgSalary FROM avg_female_salary)
很明显,第一个 CTE 在询问来自多伦多的人,第二个 CTE 在拿女性的平均工资。这是一个糟糕的命名约定的例子:
with table1 as (
SELECT DISTINCT name
FROM population
WHERE country = "Canada"
AND city = "Toronto"
), table2 as (
SELECT AVG(salary) as var1
FROM salaries
WHERE gender = "Female"
)SELECT name
, salary
FROM People
WHERE name in (SELECT DISTINCT FROM table1)
AND salary >= (SELECT var1 FROM table2)
如果只阅读最后一个查询,很难理解它在做什么。因此,请确保您的大小写一致,并且您的变量名是描述性的!
4.使用临时函数简化代码
如果你想了解更多关于临时函数的内容,看看这个,但是临时函数也是分解代码、编写更简洁的代码以及能够重用代码的好方法。
考虑下面的例子:
SELECT name
, CASE WHEN tenure < 1 THEN "analyst"
WHEN tenure BETWEEN 1 and 3 THEN "associate"
WHEN tenure BETWEEN 3 and 5 THEN "senior"
WHEN tenure > 5 THEN "vp"
ELSE "n/a"
END AS seniority
FROM employees
相反,您可以利用一个临时函数来捕获 CASE 子句。
CREATE TEMPORARY FUNCTION seniority(tenure INT64) AS (
CASE WHEN tenure < 1 THEN "analyst"
WHEN tenure BETWEEN 1 and 3 THEN "associate"
WHEN tenure BETWEEN 3 and 5 THEN "senior"
WHEN tenure > 5 THEN "vp"
ELSE "n/a"
END
);SELECT name
, seniority(tenure) as seniority
FROM employees
有了临时函数,查询本身就简单多了,可读性更好,还可以重用资历函数!
5.写有用的评论
重要的是只在需要的时候写评论。通过使用描述性的名称、编写模块化的代码以及拥有干净的编程风格,您应该不需要编写太多的注释。
也就是说,当代码本身不能解释你想要达到的目的时,注释是有用的。评论通常会回答你为什么做某事,而不是你在做什么。
下面是一个差评的例子:
# Getting names of people in Toronto, Canada
with table1 as (
SELECT DISTINCT name
FROM population
WHERE country = "Canada"
AND city = "Toronto"
)# Getting the average salary of females
, table2 as (
SELECT AVG(salary) as var1
FROM salaries
WHERE gender = "Female"
)
这些是糟糕的注释,因为它告诉我们通过阅读代码本身我们已经知道了什么。记住,评论通常会回答你为什么做某事,而不是你在做什么。
感谢阅读!
如果你坚持到了最后,我希望你学到了一些东西。正如我之前所说,学习如何编写好的 SQL 代码对于各种数据职业来说都是必不可少的,所以请确保您花时间学习如何编写好的代码!
如果你喜欢这个,请一定要关注我的未来内容,一如既往,我祝你学习一切顺利!
不确定接下来要读什么?我为你挑选了另一篇文章:
又一个!
特伦斯·申
数据科学中五种常见的距离度量,包括公式和示例
欧几里德距离、曼哈顿距离、闵可夫斯基距离、汉明距离、余弦相似度,无需编码
距离计算是数据科学中的一个常见元素。许多机器学习算法都是基于距离度量的。虽然现在你不需要手动计算距离。有一些包和函数可以用来做这件事。但是,仍然有必要了解不同的距离度量是如何工作的,以便知道哪种距离度量适合您的项目。
这篇文章将着重于给出一个关于不同距离度量的坚实的数学概念。这样,当你需要使用距离测量时,你就能清楚地知道幕后发生了什么。这非常有助于理解哪种距离测量对什么目的有用。
这将涵盖以下距离测量:
- 欧几里得距离
- 曼哈顿距离
- 闵可夫斯基距离
- 汉娩距
- 余弦相似性
让我们深入细节!
欧几里得距离
非常常用,可能我们很多人都记得初中或高中的时候用过。欧几里得距离实际上是两点之间的直线长度。如果已知两点的笛卡尔坐标,则可以使用勾股定理计算距离。
公式如下:
这是两个点 x 和 y : (5,1),(9,-2)。使用欧几里得距离,这是这两点之间的距离:
但是重要的是要记住欧几里德距离也有一些缺点。欧几里德距离不是尺度不变的。因此,基于要素的单位,距离可能会有偏差。
这就是为什么在应用欧几里德距离之前有必要对数据进行归一化。
欧几里德距离对于 2 维或 3 维数据可能是有帮助的,但是对于更高维度不是很有帮助。
曼哈顿距离
曼哈顿距离对于在统一网格(如城市或棋盘)上描述对象的向量尤其有用。一个例子是计算出租车在城市中两点之间的最短距离。它被计算为两个向量之间的绝对差之和。公式如下:
这里有一个 x 和 y:
x = [3,6,11,8]
y = [0,9,5,3]
x 和 y 之间的曼哈顿距离:
d = | 3–0 |+| 6–9 |+| 11–5 |+| 8–3 | = 3+3+6+5 = 17
曼哈顿距离在更高维度的数据中效果更好。但是不太直观。虽然这不是什么大问题。
闵可夫斯基距离
另一种流行的距离测量方法。如果你看看这个公式,你会发现它同时代表了欧几里德距离和曼哈顿距离。先来讨论一下公式。
这里,x 和 y 是两个 p 维数据对象,h 是顺序。这样定义的距离也称为 L-h 范数。
如果‘h’为 1,则成为曼哈顿距离,如果 h = 2,则成为欧几里德距离。
这里有一个例子:
x = [9,2,-1,12]
y = [-4,5,10,13]
当 h = 1 时,该公式成为曼哈顿距离公式,称为 L-1 范数:
当 h= 2 时,该公式成为欧几里德距离公式,也称为 L-2 范数:
如您所见,Minkowski 距离代表基于“h”值的其他距离度量。因此,应根据 h 值采取谨慎措施。如果是欧几里德距离,就需要把缺点考虑进去。
汉娩距
汉明距离对于寻找两个二进制向量之间的距离很有用。在数据科学或机器学习中,你会经常遇到一次性编码数据。汉明距离在这些情况和许多其他情况下都是有用的。
公式是:
这里 n 是 x 或 y 的长度,它们应该有相同的长度。如果 x 和 y 是:
x = [0,1,0,1]
y = [1,1,0,0]
那么 x 和 y 之间的距离是:
d =(| 0–1 |+| 1–1 |+| 0–0 |+| 1–0 |)/4 = 1+0+0+1 = 2/4 = 0.5
这里 4 是 x 或 y 的长度,两者都有 4 个元素。
从上面的例子中可以看出,向量需要有相同的长度。
名义属性的相似性度量
几乎类似的想法可以用于寻找标称特征或向量之间的距离。
其中 m 是匹配的数量,
p 是 x 或 y 的长度。
例如,x 和 y 是 Polly 和 Molly 的一些回答:
x = ['高',' A ','是','亚洲']
y = ['high ',' A ',' yes ',' Latino']
这里有四个元素,其中三个是相同的。x 和 y 之间的距离是:
d =(4–3)/4 = 1/4 = 0.25
现在,如果我们需要相似性而不是不相似性或距离,它只是距离的对立面。所以 x 和 y 之间的相似性是:
相似度= 1–0.25 = 0.75
余弦相似性
余弦相似度尤其用于自然语言处理。它表示两个向量之间角度的余弦,并确定两个向量是否指向几乎相似的方向。现在,这里的矢量是什么?一份文件可以由数千字组成。向量是文档中单词的频率。如果我们有五个文档,五个文档将有五个由单词频率组成的向量。这里有一个例子:
让我们找出 d1 和 d2 之间的余弦相似性
公式如下:
这里,d1.d2 表示两个向量 d1 和 d2 的点积。
D1 . D2 = 5 * 4+2 * 0+1 * 0+0 * 2+1 * 2+3 * 2+0 * 1 = 28
| | D1 | | =(5 * 5+2 * 2+1 * 1+0 * 0+1 * 1+3 * 3+0 * 0)* * 0.5 = 6.32
| | D2 | | =(4 * 4+0 * 0+0 * 0+2 * 2+2 * 2+2 * 2+1 * 1)* * 0.5 = 5.39
cos(d1,d2) = 28 / (6.32*5.39) = 0.82
这就是我们如何得到余弦相似度的。
结论
还有许多其他的距离测量方法。我试着为这篇文章挑选一些非常常见的。非常感谢您的阅读。
欢迎在推特上关注我,喜欢我的 T2 脸书页面。
更多阅读
你的数据科学工作没有影响?原因如下…
…以及对此您能做些什么
蒂姆·高夫在 unsplash.com 上提供
现在有很多沮丧的数据科学家。最近的一些调查表明,这个领域是最有可能出现不满的员工的领域之一,他们觉得自己的工作不受重视。事实上,很有可能你——这篇文章的读者——目前对你的工作不满意或感到沮丧,或者在过去的某个时候曾经如此。
要考虑的一件事是你是否能做些什么。有时,数据科学家发现自己被系统性地剥夺了权利,这是很难改变的事情,除非你身居高级领导职位。其他时候,答案就在我们家附近。我见过数据科学家扮演他们自己最大的敌人,采取的实践几乎保证他们的工作在他们的组织中不会有任何进展。
以下是我看到的数据科学工作毫无进展的五个常见原因,以及如何避免这些事情发生在你身上的一些想法。
1.这项工作首先是没有用的
有人会做无用的工作,这似乎是一个疯狂的想法,但这是糟糕的管理实践或糟糕的报告结构的一个非常常见的症状。无能或不合格的管理者继承了他们不知道如何管理的团队,或者他们不知道如何根据组织的优先事项安排工作。每次入住对他们来说都成了苦差事。他们给你工作是因为你必须做些事情来证明你的工资。对于任何员工来说,这都是一种可怕的、令人沮丧的情况,无论是数据科学家还是其他人,但以我的经验来看,这种情况在数据科学领域更常见。
如果你为任何有良好价值观的组织工作,你应该总是愿意要求你的经理将一项任务与一个目标联系起来,并问你自己这个目标是否有意义。你需要看到分配给你的特定计算任务和某种战略需求之间的直线。也许战略命令与有形的业务目标有关,如创收或降低成本,或者可能与无形的目标有关,如技能或资产建设,但你必须看到其中的联系,而且它必须对你有意义。否则有什么意义?
2.这个问题没有被很好地定义
另一种常见的情况是,有一个重要目标的链接,但它没有被很好地定义,结果你被引导到可交付成果的花园小径上。我经常看到的一个典型例子是在定义问题时语言使用不当。也许有人要求一个模型能够预测一些事情,而事实证明他们想要一个模型能够解释一些事情。因此,当他们不关心准确性,而想从推理统计模型中了解系数重要性时,你就使用一系列机器学习算法来计算准确性指标。
我发现在着手一个项目之前问以下问题是有用的:如果结果是有用的,你会如何使用它们?这是一个很有启发性的问题,可以真正揭示出作品的真正目的是什么。例如,如果答案是:我们希望将预测模型投入生产以自动化决策,那么您可以肯定,预测指标(如准确性)在您的建模方法中是最重要的。
3.你的结果没有得到很好的解释
数据科学方法是复杂的,你不能假设因为你知道你在做什么,你的经理或你团队中的其他人也会知道,或者上帝禁止外行。最优秀的数据科学家会仔细记录他们的方法。当我说“文档”时,我并不仅仅指代码中偶尔出现的带有 hashtagged 的简洁注释行。我指的是一份概述方法、数据、方法和结果讨论的研究风格文件。
如果你没有用 R Markdown 或 Jupyter 笔记本写集成文档的习惯,现在就养成这个习惯吧。下次当你有一个实质性的可交付成果时,不要只是交付结果和代码,多花几个小时把它们写下来,并解释你的方法。我做过的一些最有影响力的工作可以归结为我是如何写出来的。如果你解释得好,人们会更信任它。
4.你没有考虑到再现性
不要以一种不考虑别人拿起它并试图复制它的方式来创造作品。没有比让你的作品被遗忘更可靠的方法了,那就是让它难以复制。我无法告诉你有多少次,仅仅因为最初的创造者让我难以复制作品,我就放弃了尝试。
关注代码的质量,通过设置种子来解决随机性,评论重要的决策,保存环境变量或工作空间。保持 git repo 的更新。捕获运行代码的系统和环境的记录(通过像 R 中的 sessionInfo()或其他语言中的等效函数)。向他人展示你已经尽了最大努力让你的作品具有可复制性,他们会同样信任你和钦佩你。
5.当心误解
当你交出成果时,你的工作并没有结束。一旦你的工作开始在组织内传播,外行人很容易误解你的工作。弱显著因素可能突然变成高度预测因素。拟合不好的模型,会突然变成参考模型。
将你的名字附在工作上,努力确保你参与到后续工作中,即使只是为了倾听以获得安慰。如果你听到了错误的解释,不要羞于跟进,与相关人员一起纠正。请记住,你的同事通常都有自己的议程,他们会试图利用你的工作来构建一个支持这些议程的故事。要求看到或听到他们的叙述,并确保你的工作没有被政治滥用(即使是无意的)。随着时间的推移,这些纠正性的干预会让你的意见更有价值,让你被视为真理的保护者。
这些情况你听起来熟悉吗?你认为我还忽略了其他因素吗?如果是这样,请随时发表评论。
最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在 LinkedIn 或 Twitter 上找到我。也可以看看我关于drkeithmcnulty.com的博客或者我关于人物分析的 教科书 。
你应该知道的 Python 中的五个 Dunder 方法
图片来自 Pixabay 的 Joshua Woroniecki
Dunder 方法也称为魔术方法,是理解 Python 所必需的
在我的上一篇文章中,我谈到了面向对象编程(OOP)。我特别提到了一个神奇的方法__init__
,在 OOP 术语中也称为构造方法。
__init__
的神奇之处在于,每当一个对象被自动创建时,它就会被调用。但从任何意义上来说,它都不是唯一的。Python 为我们提供了许多其他神奇的方法,我们最终甚至在不知道它们的情况下使用了它们。曾经在列表中使用过len()
、print()
或[]
运算符吗?你一直在用邓德的方法。
在这篇文章中,我将谈论五个最常用的魔法函数或“dunder”方法。
1.符魔战法:__add__ , __sub__ , __mul__ , __truediv__ , __lt__ , __gt__
Python 中的一切都是对象,从数据类型int
、str
、float
到我们在数据科学中使用的模型。我们可以在一个对象上调用方法,比如这个 str 对象
Fname = "Rahul"# Now, we can use various methods defined in the string class using the below syntaxFname.lower()
但是,正如我们所知,我们也可以使用+
操作符来连接多个字符串。
Lname = "Agarwal"
print(Fname + Lname)
------------------------------------------------------------------
RahulAgarwal
那么,加法运算符为什么起作用呢? 我的意思是 String 对象遇到加号怎么知道该怎么做?在str
类里怎么写?同样的+
操作在整数对象的情况下以不同的方式发生。因此 运算符+在字符串和整数的情况下表现不同 (喜欢的人称之为—运算符重载)。
那么,我们可以添加任意两个对象吗?让我们试着从我们的初级 Account 类中添加两个对象。
由于Account类型的对象不支持操作数+,因此如预期的那样失败。但是我们可以使用我们的神奇方法__add__
将+
的支持添加到我们的 Account 类中
class Account:
def __init__(self, account_name, balance=0):
self.account_name = account_name
self.balance = balance
def __add__(self,acc):
if isinstance(acc,Account):
return self.balance + acc.balance
raise Exception(f"{acc} is not of class Account")
这里我们给我们的类添加了一个神奇的方法__add__
,它有两个参数——self
和acc
。我们首先检查acc
是否是 class account,如果是,当我们添加这些帐户时,我们返回余额的总和。如果我们向 account 添加除 account 类对象之外的任何东西,我们将看到一个描述性错误。让我们试一试:
因此,我们可以添加任意两个对象。事实上,我们也有各种各样的其他运营商不同的魔术方法。
__sub__
为减法(-
)__mul__
用于乘法运算(*
)__truediv__
为除法(/
)__eq__
为相等(==
)__lt__
为小于(<
)__gt__
为大于(>
)__le__
为小于或等于(≤
)__ge__
为大于等于(≥
)
作为一个运行示例,我将通过创建一个名为**Complex**
的类来处理复数,从而尝试解释所有这些概念。不要担心Complex
只是这个类的名字,我会尽量保持简单。
所以下面,我创建一个简单的方法__add__
,把两个复数相加,或者一个复数加一个int/float
。它首先检查被添加的数字是否属于类型int
或float
或Complex
。根据要添加的数字的类型,我们进行所需的添加。我们还使用isinstance
函数来检查另一个对象的类型。请务必阅读评论。
它可以用作:
a = Complex(3,4)
b = Complex(4,5)
print(a+b)
你现在应该能够理解下面的代码,它允许我们将add
、subtract
、multiply
和divide
复数和标量(float
、int
等)进行运算。).看看这些方法如何依次返回一个复数。以下代码还提供了使用__eq__
、__lt__
、__gt__
比较两个复数的功能
你真的不需要理解所有的复数数学,但是我已经在这门课上尝试使用了大部分的魔法方法。也许通读一下__add__
和__eq__
一。
现在我们可以使用我们的Complex
类:
2.但是为什么复数会打印成这个随机的字符串呢?— str 和 repr
啊!你抓到我了。这让我们看到了另一个 dunder 方法,它让我们在我们的对象上使用 print 方法,这个对象叫做__str__
。主要思想还是当我们调用print(object)
时,它调用对象中的__str__
方法。下面是我们如何在我们的Complex
类中使用它。
class Complex:
def __init__(self, re=0, im=0):
self.re = re
self.im = im .....
..... def __str__(self):
if self.im>=0:
return f"{self.re}+{self.im}i"
else:
return f"{self.re}{self.im}i"
我们现在可以重新检查输出:
所以现在,我们的物体以一种更好的方式打印出来。但是,如果我们在笔记本中尝试执行下面的操作,就不会调用__str__
方法:
这是因为我们没有在上面的代码中打印,因此没有调用__str__
方法。在这种情况下,会调用另一个名为__repr__
的神奇方法。我们可以在我们的类中添加它,以获得与打印相同的结果(我们也可以用不同的方式实现它)。这是邓德方法中的邓德方法。相当不错!!!
def __repr__(self):
return self.__str__()
3.我会抓到你的。那么,len 方法也是这样工作的吗?len
len()
是另一个非常适合字符串、列表和矩阵等等的函数。为了在我们的复数类中使用这个函数,我们可以使用__len__
魔法方法,尽管在这种情况下,这并不是一个有效的复数用例,因为按照文档,__len__
的返回类型需要是一个int
。
class Complex:
def __init__(self, re=0, im=0):
self.re = re
self.im = im ......
...... def __len__(self):
# This function return type needs to be an int
return int(math.sqrt(self.re**2 + self.im**2))
下面是它的用法:
4.但是赋值操作呢?
我们知道+
操作符是如何处理对象的。但是你想过为什么下面的+=
会起作用吗?例如
myStr = "This blog"
otherStr = " is awesome"myStr**+=**otherStr
print(myStr)
这让我们想到了另一组邓德方法,称为赋值邓德方法,包括__iadd__
、__isub__
、__imul__
、__itruediv__
和许多其他方法。
因此,如果我们只是将下面的方法__iadd__
添加到我们的类中,我们也能够进行基于赋值的添加。
class Complex:
.....
def __iadd__(self, other):
if isinstance(other, int) or isinstance(other, float):
return Complex(self.re + other,self.im)
elif isinstance(other, Complex):
return Complex(self.re + other.re , self.im + other.im)
else:
raise TypeError
并将其用作:
5.你的类对象能支持索引吗?
有时对象可能包含列表,我们可能需要索引对象以从列表中获取值。为了理解这一点,让我们举一个不同的例子。假设你是一家帮助用户交易股票的公司。每个用户将有一个每日交易簿,其中包含用户一天的交易/交易信息。我们可以通过以下方式实现这样一个类:
class TrasnsactionBook:
def __init__(self, user_id, shares=[]):
self.user_id = user_id
self.shares = shares
def add_trade(self, name , quantity, buySell):
self.shares.append([name,quantity,buySell])
**def __getitem__(self, i):
return self.shares[i]**
你注意到这里的__getitem__
了吗?这实际上允许我们在这个特定类的对象上使用索引,使用:
根据我们使用的指数,我们可以得到用户完成的第一笔交易或第二笔交易。这只是一个简单的例子,但是当您使用索引时,您可以设置您的对象来获得更多的信息。
结论
Python 是一种神奇的语言,Python 中有很多即使是高级用户也可能不知道的构造。邓德方法可能就是其中之一。我希望通过这篇文章,你能很好地了解 Python 提供的各种 dunder 方法,并理解如何自己实现它们。如果你想了解更多的 dunder 方法,看看 Rafe Kettler 的博客。
如果你想了解更多关于 Python 的知识,我想从密歇根大学调出一门关于学习 中级 Python 的优秀课程。一定要去看看。
我以后也会写更多这样的帖子。让我知道你对这个系列的看法。在 媒体 关注我或者订阅我的 博客 了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter @mlwhiz 联系
此外,一个小小的免责声明——这篇文章中可能会有一些相关资源的附属链接,因为分享知识从来都不是一个坏主意。
这个故事最初发表在内置上。
数据分析师的五个基本 Excel 函数
是时候增强你的电子表格肌肉了。
Excel 对数据分析师很有用
很多数据科学家和数据分析师会经常告诉你,要想打入行业,就要学习 Python 或者 R。但是著名的电子表格应用软件 Microsoft Excel 仍然很受欢迎——在分析数据方面,有时比编程语言更好。一个好的 Excel 电子表格应该将复杂的原始数据转换成组织中任何人都能理解的可读文档。在本文中,我们将了解所有数据分析师都应该知道的五个基本 Excel 函数。
计数空白
原始数据可能是杂乱的,有时它可能包含丢失的值,尤其是当这些数据是在现实世界中收集的时候。在 Python 中,我们可以使用 isna()之类的方法来检测丢失的值。但是,在 Excel 中使用 COUNTBLANK 函数也可以做到这一点。
COUNTBLANK 将计算给定范围内空白单元格的数量。
使用 COUNTBLANK 函数检查缺失值。图片作者。
该 Excel 函数的公式为:
=COUNTBLANK(范围)
苏米夫斯
最著名和最基本的 Excel 函数之一是 SUM 函数。有时我们可能希望使用 SUM,但是也使用一个标准将单元格从求和中排除。这就是 SUMIFS 的用武之地。
SUMIFS 允许我们对给定范围内的值求和,但只对符合给定条件的值求和。根据需要,可以为该函数提供任意多的标准。
使用 SUMIFS 函数计算不同地点的雇员数。图片作者。
该 Excel 函数的公式为:
=SUMIFS(sum_range,criteria_range1,criteria1,…)
等级
RANK 函数可用于返回某个数值在与其他数值列表进行比较时的排名。在数据分析中,排序对于了解特定值在有序数组中的位置非常重要。还有一个类似的函数 PERCENTRANK,它以数据集范围的百分比形式返回排名。
需要注意的是,如果在给定的列表或数组中找不到值,Excel 将返回#N/A 错误。对于 PERCENTRANK 来说,情况并非如此。
使用 RANK 函数按员工数量对地点进行排名。图片作者。
该 Excel 函数的公式为:
=RANK(数字,列表)
纵向查找函数
VLOOKUP 是任何数据分析师都应该知道的最重要的功能之一。它可以用来检索或查找垂直排列的表格中的数据。这非常有用,因为它可以用来自动查找另一个电子表格中的数据,只要每行都有一个 ID。
表的 ID 列必须是第一列。VLOOKUP 函数中的第三个参数可用于引用包含要检索的数据的列。需要注意的是,这个参数在 Excel 中是从 1 开始的。这意味着值 2 将得到第 2 列,值 3 将得到第 3 列,依此类推。这与 Python 中的列表索引不同,后者是基于 0 的。
VLOOKUP 函数中的另外两个参数指的是查找值(或正在检索的行的 ID)和表本身的范围。
使用 VLOOKUP 函数查找不同位置的数据。图片作者。
该 Excel 函数的公式为:
=VLOOKUP(查找值,表数组,列索引号)
IFERROR
如果您要向公司中的其他人展示 Excel 电子表格,那么当函数中出现错误时,在单元格中使用默认值会很有用。当其他用户不理解错误的含义时,或者当计算中出现错误(如默认为 0)时单元格的值已知时,这可能特别有用。
IFERROR 函数可以做到这一点。这个函数只接受两个参数,第一个是函数,第二个是函数抛出错误时的默认值。如果函数没有抛出错误,那么值将正常输出。
使用 IFERROR 函数处理 Excel 错误。图片作者。
该 Excel 函数的公式为:
=IFERROR(值,值 _if_error)
现在你知道了!这是数据科学家和数据分析师应该知道的 Microsoft Excel 的五个基本功能。尽管您需要知道这五个函数,但是请记住,还有许多 Excel 函数可以使用,并且通常有一个函数可以完成您的工作。
VLOOKUP 是最臭名昭著的功能之一,在工作描述和面试中会被问到。SUMIFS 之类的函数非常常见,几乎在所有有用的电子表格中都可以找到它们。事实上,本文中的所有函数在数据分析中都很常见。您认为还有其他 Excel 函数对于数据分析是必不可少的吗?下面分享一下。
创建优秀数据科学家简历的五种基本方法
办公时间
如何写一份展示你的分析能力和商业头脑的简历
数据科学家角色是 2021 年薪酬最高、最有声望的角色之一。由于过去十年的数字化转型,技术成为我们生活的中心,数据可以用来向企业高管讲述令人信服的故事,数据科学家成为受欢迎的专业人士。这种转变既有好的一面,也有不好的一面。先说好的。如果你是数据科学家,意味着你会很抢手,找到工作的几率很高。你可以选择你想为之工作的公司,你会被这种选择宠坏。
那么什么是不好的呢?嗯,这意味着作为一名正在找工作的数据科学家,你将面临更多的竞争,因为其他数据科学家将竞争最好的公司,一个不仅工资高,而且简历也好看的公司。因此,接下来的问题是如何比其他候选人更有优势,从而让你得到招聘人员和招聘经理的注意。
作为科技行业的招聘经理和许多科技工作的面试官——不仅是软件开发人员和工程经理,还有数据分析师、产品经理、UX 设计师、内容作者、项目经理和技术招聘人员——我已经看到了很多科技工作的简历和突出的东西。这就是为什么我创建了一个完美简历模板样本来帮助科技行业的求职者。那些简历出众的人在面试中的表现也高于平均水平。这是因为他们展现了自己最好的一面,强调了重要的信息,让面试官可以深入了解。因此,他们的面试更有针对性,也更流畅。
创建优秀数据科学家简历有五种基本方法。伟大的数据科学家的简历是有效的,可以展示你的分析技能和商业头脑,获得多次面试,并让你得到你想要的工作。
事不宜迟,以下是创建数据科学家简历时应该采用的五种基本方法:
- 🦄专注于你的专业。
- 🏆量化你的成就。
- 🎯出示证明。
- 💡让它可以扫描。
- 🤖丢弃无关信息。
1.🦄专注于你的专业
米利安·耶西耶在 Unsplash 上拍摄的照片
在行业和数据科学家社区中,您最出名的一件事是什么?它可能是一项专业技能,也可能是特定类型的公司或环境。比如提高流失率或者在 fintech 公司工作。不知道你以什么闻名?回顾过去几年你的职业生涯,你参与过的项目,你工作过的公司,找出一些模式。在任何事情上变得更好的关键是大量的持续练习,所以你的专长很可能是你一直在重复做的事情。
一旦你确定了自己的专长,在简历的简短摘要部分突出它。此外,在你所做的每份工作的工作总结中,要突出你的特长。
2.🏆量化你的成就
比较这三个成就的例子:
- 作为首席数据科学家,我曾参与 XYZ 公司的一个定价项目。
- 作为首席数据科学家,我参与了 XYZ 公司最大的定价项目之一。这个项目持续了三个多月,我开发了一个情感分析模型。
- 作为 XYZ 公司的首席数据科学家,我参与了一个市场网站的定价项目,该网站每月有 300 万独立访问者。该项目的目的是增加客户的平均支出,作为项目的一部分,我开发了一个情绪分析模型,利用了 2 亿多条现有记录。到财年结束时,情绪分析模型将客户的平均支出提高了 20%。
正如您所看到的,第三个例子非常突出,因为它不仅解释了项目的复杂性,还量化了候选人在行业指标中交付的影响。看上面的例子也可以看出考生的特长是大数据分析。
3.🎯出示证据
在 Unsplash 上由 Austin Distel 拍摄的照片
招聘经理或招聘人员如何知道你真的有能力做到你在简历中所说的或已经做到的事情?通过看到证据。证明可以通过以下三种方式之一作为简历的一部分:
- 你过去和现在的同事的评价和 360 度反馈。
- 你的在线作品(如个人品牌、网站、作品集)。
- 你获得的奖励,只要与你的职业相关。
你可以看看如何在我创建的样本简历模板中展示这样的证明。
4.💡使其可扫描
Adeolu Eletu 在 Unsplash 上拍照
众所周知,招聘人员和招聘经理浏览简历的时间不超过 10 秒钟。但这并不意味着写一份包含重要信息的可靠简历毫无意义。这是因为如果有一份简历引起了他们的注意,招聘人员和招聘经理会花更多的时间来看它。他们可能不会立即看到它,但他们肯定会回来看的。因此,关键是让你的简历易于浏览,这样招聘人员或招聘经理会在十秒钟内做出决定,他们想花更多的时间审查你的简历。
为了使你的简历易于浏览,每个标题使用合适的字体大小和颜色,将某些关键词(如你的专业)加粗,将相关信息分组,用项目符号列出项目,添加空格以提高可读性,最后但同样重要的是,按照重要性从上到下排列信息。这些是一些简单而有效的方法。
5.🤖丢弃无关信息
马克·弗莱彻·布朗在 Unsplash 上的照片
“少即是多。”你可能听过这句话,但是你真的在实践中运用过这个理论吗——尤其是在你的简历中?
当你的简历有四五页那么长,包含了太多的信息,会让招聘经理和招聘人员不知所措。风险是用所有不相关和过时的信息稀释你的重要成就。或者更糟的是,他们可能会完全丢弃你的简历。
例如,如果你在几年前从开发人员转行到数据科学家,你不需要列出你作为软件开发人员的所有就业历史。
同样,如果你已经在这个行业工作了十多年,并且正在申请领导职位,那么把你的第一次实习经历从你的工作经历中去掉也是可以的。
“完美的实现,不是当没有更多可以添加的时候,而是当没有什么可以拿走的时候。”― 安托万·德·圣·埃克苏佩里
在你的数据科学家简历上投资会有回报的
由格伦·卡斯滕斯-彼得斯在 Unsplash 上拍摄的照片
一份好的简历不仅能让你获得面试机会,还能让你获得工作机会。我们都知道这一点:第一印象很重要。你对潜在雇主的第一印象始于他们看到你简历的那一刻,而不是你第一次面试见到他们的时候。此外,数据科学家的成功在于让数据有助于影响现实世界的行动和商业决策,作为数据科学家,没有比在自己的简历中应用这一技能更好的方式了。
总而言之,以下是创建优秀数据科学家简历的五个基本方法,它将尽可能地展现你最好的一面:
- 🦄专注于你的专业。
- 🏆量化你的成就。
- 🎯出示证明。
- 💡让它可以扫描。
- 🤖丢弃无关信息。
📩注册订阅作者的时事通讯,定期获得关于你科技职业的建议和资源。您还将立即收到一个链接和密码,为您的职业发展下载免费赠品。
更好的图像处理
机器学习从业者越来越多地转向 GANs 的力量进行图像处理,了解这五个。
机器学习实践者越来越多地转向图像处理的生成对抗网络(GANs)的力量。真正受益于使用 GANs 的应用程序包括:从基于文本的描述中生成艺术和照片、放大图像、跨域传输图像(例如,将白天场景改为夜晚场景)以及许多其他应用程序。为了实现这样的结果,已经设计了许多增强的 GAN 架构,它们具有自己的独特特征来解决特定的图像处理问题。
我们选择近距离观察这五个今日头条的 gan,因为它们提供了广泛的功能,从放大图像到从基于文本的描述创建全新的图像:
- 条件 GAN
- 堆叠氮化镓
- 信息最大化
- 超分辨率氮化镓
- Pix2Pix
如果你需要快速复习 GAN,请查看我们的博客探索生成对抗网络,在那里我们回顾了 GAN 如何训练两个神经网络:生成器和鉴别器,它们学习生成越来越逼真的图像,同时提高其将图像分类为真假的能力。
条件 GAN
标准 GANs 的一个挑战是无法控制生成的图像类型。生成器简单地从随机噪声开始,并且随着时间的推移重复地创建希望趋向于表示训练图像的图像。
一个条件 GAN (cGAN),通过利用标签数据(又名类标签)等附加信息来解决这个问题。这也可以导致更稳定或更快的训练,同时潜在地提高生成图像的质量。例如,一个带有不同类型的蘑菇图像和标签的 cGAN 可以被训练成只产生和辨别那些准备采摘的蘑菇。由此产生的模型可以作为工业机器人计算机视觉的基础,用于寻找和采摘蘑菇。如果没有这样的条件,标准 GAN(有时称为无条件 GAN )仅仅依赖于将潜在空间中的数据映射到生成图像的数据。
实现 cGANs 有不同的方法,但一种方法是通过向鉴别器和生成器输入类标签来调节它们。以下示例显示了用于生成手写数字图像的标准 GAN,该标准 GAN 使用标签数据进行了增强,以仅生成数字 8 和 0 的图像:
图 1 :一个 cGAN,其中类标签被输入到生成器和鉴别器以控制输出。图像由http://www.perceptilabs.com感知。
这里,标签可以被一键编码以去除平凡性,然后作为附加层输入到鉴别器和生成器,在那里它们然后与它们各自的图像输入连接(即,与生成器的噪声连接,以及与生成器的训练集连接)。因此,在训练期间,两个神经网络都以图像类别标签为条件。
概要:当您需要控制生成的内容时,请使用 cGAN(例如,生成训练数据的子集)。
堆叠氮化镓
如果我们能让电脑为我们画一幅画,那不是很酷吗?好吧,这就是 Stacked GAN (StackGAN)背后的灵感,在论文 StackGAN:利用堆叠生成对抗网络进行文本到照片级逼真图像合成中有所描述。
在这篇论文中,作者将 StackGAN 描述为一个基本的两阶段草图细化过程,类似于画家使用的先画出一般元素,然后再细化的过程:
第一阶段 GAN:它根据给定的文本描述勾画出物体的原始形状和基本颜色,并从随机噪声向量中绘制背景布局,产生低分辨率图像。
第二阶段 GAN:它纠正第一阶段低分辨率图像中的缺陷,并通过再次阅读文本描述来完成物体的细节,产生高分辨率照片级图像。
作者提供了其模型架构的以下概述:
图 2:stack gan 模型架构概述,图片* 来源 。*
虽然使用常规 GAN 可以解决这一问题,但输出图像可能缺乏细节,并且分辨率可能会较低。StackGAN 的两阶段架构基于 cgan 的思想来解决这一问题,正如作者在他们的论文中所述:通过再次对第一阶段的结果和文本进行调节,第二阶段的 GAN 学习捕捉第一阶段 GAN 忽略的文本信息,并为对象绘制更多细节。从粗略对准的低分辨率图像生成的模型分布的支持具有与图像分布的支持相交的更好的概率。这是第二阶段氮化镓能够产生更好的高分辨率图像的根本原因。**
要了解 StackGAN 的更多信息,请查看作者的 GitHub repo ,他们在这里提供了模型以及鸟类和花卉的图像。
概要:当你需要从一个完全不同的表现形式(例如,从基于文本的描述)生成图像时,使用 StackGAN。
信息最大化
与 cGAN 类似,信息最大化 GAN* (InfoGAN)利用附加信息来提供对生成内容的更多控制。在这样做的过程中,它可以通过无人监督的训练学会理清图像的各个方面,如发型、物体的存在或情绪。然后,该信息可以用于控制所生成图像的某些方面。例如,给定一些戴眼镜的人脸图像,可以训练 InfoGAN 为眼镜解开像素,然后使用它生成戴眼镜的新人脸。*
使用 InfoGAN,一个或多个控制变量与噪声一起输入到发生器。使用包含在称为辅助模型的附加模型中的互信息来训练生成器,该辅助模型与鉴别器共享相同的权重,但是预测用于生成图像的控制变量的值。这种交互信息是通过对发生器生成的图像进行观察获得的。与鉴别器一起,辅助模型训练生成器,使得 InfoGAN 学习生成/识别伪图像与真实图像,并且捕获所生成图像的显著属性,使得它学习改进图像生成。下图总结了这种架构:
图 3: 对 InfoGAN 架构的总结。图像由 感知。
有关 InfoGAN 的更多信息,请查看这篇文章。
概要:当你需要将图像的某些特征分解出来,合成为新生成的图像时,可以使用 InfoGAN。
超分辨率氮化镓
图像增强领域正在发展,越来越依赖于机器学习(ML)算法,而不是双三次插值等传统的统计方法。一种超分辨率 GAN* (SRGAN)就是这样一种 ML 方法,可以将图像升级到超高分辨率。*
SRGAN 利用 GANs 的对抗性,结合深度神经网络,来学习如何生成放大的图像(分辨率高达原始图像的四倍)。这些产生的超分辨率图像具有更好的准确性,并且通常获得较高的平均意见得分 (MOS)。
为了训练 SRGAN,首先将高分辨率图像下采样为低分辨率图像,并输入到生成器中。然后,生成器会尝试将该图像升采样到超分辨率。鉴别器用于将生成的超分辨率图像与原始高分辨率图像进行比较。鉴频器的 GAN 损耗然后反向传播到鉴频器和发生器,如下所示:
图 4: SRGAN 架构。LR =低分辨率图像,HR =高分辨率图像,SR =超分辨率图像,X =输入到鉴别器,D(X)= HR 和 SR 之间的鉴别器分类,图像 来源 。
发生器使用多个卷积神经网络( CNNs 和resnet,以及批量标准化层和激活函数的 ParametricReLU。这些方法首先对图像进行下采样,然后对其进行上采样以生成超分辨率图像。类似地,鉴别器使用一系列 CNN 以及密集层、泄漏 ReLU 和 sigmoid 激活来确定图像是原始高分辨率图像还是生成器输出的超分辨率图像。
要了解更多关于 SRGANs 的信息,请查看这篇文章。
总结:当您需要放大图像,同时恢复或保留精细、高保真的细节时,请使用 SRGAN。
Pix2Pix
正如我们在博客中讨论的,机器学习被用于图像处理和计算机视觉的五大方式,对象分割是一种将数字图像中的像素组划分为片段的方法,这些片段可以作为一个或多个图像中的对象进行标记、定位,甚至跟踪。
分割也可用于将输入图像转换为输出图像,用于各种目的,例如从标签图合成照片,从边缘图重建对象,以及对黑白图像进行着色。
分割可以使用 Pix2Pix 来完成,这是一种用于图像到图像翻译的 cGAN,其中 PatchGAN 鉴别器首先被训练来分类使用这些翻译生成的图像是真是假,然后被用来训练基于 U-Net 的生成器来生成越来越可信的翻译。使用 cGAN 意味着该模型可以用于各种翻译,而无条件的 GAN 需要额外的元素,如 L2 回归,以调节不同类型翻译的输出。
图 5: 使用 Pix2Pix 着色的例子。在这里,鞋子的黑白图纸(输入)与它们的训练数据(地面真实)一起显示,Pix2Pix 生成的图像(输出),图像 来源 。
下图显示了在给黑白图像着色的情况下,如何首先训练 Pix2Pix 中的鉴别器:
图 6: 先在 Pix2Pix 架构中训练鉴别器。图像由 感知器 组成。
这里,黑白图像作为输入被提供给生成器,该生成器产生彩色版本(输出)。鉴别器然后执行两个比较:第一个比较输入与目标图像(即,与表示地面真实情况的训练数据),第二个比较输入与输出(即,生成的图像)。然后一个优化器根据两次比较的分类误差调整鉴别器的权重。
现在训练了鉴别器,然后可以用它来训练发生器:
图 7: 使用训练好的鉴别器训练 Pix2Pix GAN 中的发生器。图像由http://www.perceptilabs.com感知。
这里,输入图像被输入到发生器和鉴别器中。(经过训练的)鉴别器将输入图像与发生器的输出进行比较,并将输出与目标图像进行比较。优化器然后调整生成器的权重,直到它被训练到生成器能够在大部分时间欺骗鉴别器的程度。
关于 Pix2Pix 的更多信息,请看这篇文章。另外,请务必查看这个 GitHub repo 。
****总结:当你需要将源图像的某个方面转换成生成的图像时,使用 Pix2Pix GAN。
结论
GANs,更具体地说是它们的鉴别器和发生器,可以用多种方式构建,以解决各种各样的图像处理问题。以下总结可帮助您选择适合您应用的 GAN:
- cGAN :控制(例如,限制)GAN 应该训练的分类。
- StackGAN :使用基于文本的描述作为创建图像的命令。
- InfoGAN :理清您想要生成的图像的具体方面。
- SRGAN :在保持精细细节的同时,放大图像。
- pix2pix :分割和转换图像(例如,给图像着色)。
您目前与哪种类型的甘一起工作?
感知实验室的 GAN 组件目前提供基本的 GAN 功能,如我们的 GAN 教程所示。随着我们继续增强 PerceptiLabs,我们很想知道您希望增加对这些不同 GAN 架构的什么类型的支持。有空的话,请通过 PerceptiLabs 论坛的总或问题/反馈频道告诉我们。
关于在数据科学领域建立职业生涯的五个硬道理
为什么人们觉得在数据科学领域找到第一份工作很难
micha Parzuchowski 在 Unsplash 上的照片
在谷歌上简单搜索在数据科学领域发展职业,你会看到一长串详尽的技能清单。从 python 编程到应用统计学,具备熟练的沟通技巧,制作报表和仪表盘。除了这种混乱之外,还有各种各样不同要求的工作。例如,一家金融科技公司可能会寻找数学博士,而一家基于产品的公司则需要一名精明的统计学家来设计和运行他们的 A/B 测试实验,以推动决策科学。
因此,那些仍然不确定自己是否想要这份工作的有志之士,会因为这一大堆必需技能而沮丧。
事实 1——没有人能做所有的事情。掌握数据知识,然后缩小范围。
事实是,没有一个数据科学家或分析师拥有所有这些技能。他们中的很多人除了基本的数据素养之外,还擅长 2-3 种技能,这使得他们不可替代。
这里的一个好方法是获得足够的数学和统计知识来做以下事情:
- 扩大可用方法的适用范围。如果你不知道某样东西的存在,你将如何应用它?
- 选择正确的方法——从可用的技术中选择,评估哪种方法最适合您的场景。
- 如何应用这些方法— 了解将一种技术应用于您的问题的复杂性。能够配置和优化。
真相 2——体验的悖论
获得这一职位的另一个挑战是,大多数公司希望有经验的科学家能够推动决策并完善他们的商业模式。那新手怎么打入 DS 呢?
你一定遇到过关于需要经验才能获得经验的悖论的迷因。这些迷因适用于 DS。唯一的解决办法是建立一个坚实的工作组合,展示你在该领域的专业知识。
真相#3 —新毕业的数据科学家激增
我们有来自大学学位课程、训练营或 MOOCs 的毕业生。每份工作的合格候选人数量已经从 25 份简历猛增至 100 份简历,而且只会随着时间的推移而增长。
这不是你应该担心的事情,但却是需要警惕的事情。它会促使你有一个更聪明的计划。
真相 4——编程是成为优秀数据科学家的必经之路
在一定程度上,您可以使用 Excel 或其他 BI 工具(如 Tableau)进行分析甚至建模,但它们不提供对不同数据集运行多种分析的灵活性。
再现性一直是一个主要的关注点,这就是为什么我们现在正在寻找为数据和 ML 管道建立版本控制的团队。到目前为止,还没有一个工具提供这种功能。即使是这样,任何一种工具处理的可能性也是巨大的。
真相 5——无论你来自哪里,领域知识都是关键
我工作的最后一家公司向数据科学候选人发送研究论文,以检查他们是否能够理解生物医学问题和数据。这项练习告知团队候选人做出决策和推动发展的能力。业务理解基本上是数据科学范式和现实世界问题的实用性的交集。
它帮助您定义正确的问题、确定正确产品线的优先级、选择正确的数据源、衡量正确的指标,进而帮助企业更快发展。
一大部分新人发现很难结合该领域的经验来发展领域知识。
通告
在 4 月的最后一周,我将做一个关于如何在数据科学领域找到工作的免费网络研讨会,我将分享如何制定战略、写简历和求职信的技巧,以及你可以在世界不同地区申请的工作。
为了更好地帮助你,我需要你填写这张表格。只需要 1 分钟!
和我联系!
如果你觉得这有帮助,可以考虑订阅我的时事通讯,因为我每周都会继续揭开这些挑战的神秘面纱。
如果您有一些建议、问题或想法,请随时回复本博客或对视频发表评论,或者您可以通过 Twitter 或 LinkedIn 与我联系。
我从第一次数据科学演示失败中学到的五个教训
糟糕的演讲令人沮丧,但这里是我学到的五件最重要的事情
埃德温·安德拉德在 Unsplash 上的照片
引人注目的视觉效果。明确的信息。可行的信号。
在我的第一次数据科学演示中,经过数周的辛勤工作,我希望向我的观众传达的所有内容的描述。我坚信我的项目的结果会令人信服,足以引起敬畏和赞美。
但是相反,我的第一次演讲(惊喜!)翻牌了。
观众并不买账。
我高估了自己的表现,没有得到预期的回应。我没有回答我分析中的一个关键问题。
立刻,我的信心死了。我开始紧张地结巴起来,当我紧紧抓住我的桌子时,东西掉在了地板上。
这凸显了任何数据科学家都经常遇到的情况,尤其是像我这样的第一次尝试的人,他们对任何失败的第一反应就是放弃。但这可能是我们第一次证明自己的好机会。
作为数据科学家,我们对自己从事的项目充满激情和兴奋是很正常的。当我们的交付没有得到同样的热情时,我们也同样感到失望。
停止。呼吸…
每当我被一个具有挑战性的问题困住时,我的第一反应就是给出我想到的第一个答案。我意识到,快速但考虑不周的回应只会让我面临更大的失败。
如果你发现自己处于这种境地,给自己一些时间去寻找正确的答案是可以的。你的听众会理解的。我们变得不耐烦是因为我们害怕有人会发现我们。但是一个框架不好的答案更有可能暴露我们的缺点。因此,我明白了在一头扎进去寻找直接解决办法之前给自己时间是多么重要。
这也很好地提醒了我,站在观众面前分享我已经研究了几周或几天,像任何数据科学家调整模型一样打磨和改进的东西,我应该为自己感到自豪。数据科学是艰难的。我完成了整个项目,并证明了这一点。我已经证明了我有能力。
愿意接受失败。
失败有助于我们成为更好的数据科学家。
在一次糟糕的陈述(以及任何陈述)之后,我通常会痛打自己一顿。但更重要的是在智力上诚实。接受失败并不意味着我是一个失败者。相反,我没能有效地发表演讲。拥有这些信息有助于我承认自己的错误,并明白我可以做得更好。我唯一失败的时候是我放弃的时候。
分解问题
在数据科学中,我学习从噪音中提取信号。可能是知识差距吧。说话仓促、紧张。复杂的视觉效果。花在技术细节上的时间太多。向你的观众传达错误的信息。或者不清楚的发现。
为了避免犯这些错误,我会花时间找出问题所在,把它分成小块,并运用我的技能。
我也学会问正确的问题。我意识到,如果我不知道我不知道的事情,我就无法取得进步。每当我对某件事不清楚的时候,我会毫不犹豫地向我的听众寻求澄清——想要修正某件事并不可耻。正如企业家和数据科学家达米安·明格尔所说,“如果你想帮助个人,要感同身受,并提出问题;这样你也可以开始更好地了解他们的旅程。”
如果我足够在乎某件事,我会不顾一切去追求它。
拥抱和适应变化
相信我的能力对于接受我能解决的问题是至关重要的。我怎样才能让我的下一次演讲更吸引人呢?还是更有意义?
“一只鞋适合所有人”的方法不允许在特殊情况下实现最佳交付。因此,在给定的情况下,开出实际可行的解决方案是恰当的。也许我的演讲风格适合我的公共演讲课,或者我的队友认为视觉效果很棒。然而,为了发展更深层次的专业知识,远离不再有用的东西是很重要的。也许我需要改变我的分析工具或采用新技术。我更好地准备调整我的心态,以不同的方式思考问题,并邀请新的观点。
策划下一步行动,继续前进
未能交付高质量的演示并不意味着一切都结束了。我经常犯的两个错误是,我根据自己的工作表现来评价自己。第二,我允许对失败的恐惧阻碍未来的前景。
失败的积极意义在于,我可以预见一个变得更好的机会。这是一个设定新目标的机会,走出我的舒适区,战略性地提前计划。这个原则适用于我的整个工作生涯。无论我的演示结果如何,我都会为意想不到的事情做准备。我也准备更加努力地工作。
我的目标是传达正确的信息。如果我搞砸了,我会弥补的。一旦我完成了这个壮举,我不会让恐惧阻止我,而是继续我的下一个项目。继续前进,让未来的成功压倒过去的失败。
认识问题、确定解决方案并做出改进是数据科学各个方面不可或缺的一部分。当然,我再也回不到那 15 分钟了,但是随着我承认并实践这些原则,我的能力也在增长。
我作为一个傻瓜学到的五个经验教训有助于掌握数据科学
当你广知道,你就在万物中看到它—宫本武藏,《五环之书》**
有趣的事实:右边的那两个人赌我举不起来,输了 20 美元
一年多前,我开始了我的数据科学之旅,这主要是为了让我在全球疫情期间以更有成效的方式保持忙碌,相比之下,我更早的计划是试图让它成为一个 Twitch streamer ( 我没有合适的相机设置)。从那以后,我完成了几门课程,做了几个项目,并且写了我的经历。虽然其他人可能已经完成了更多,但这仍然是一个不错的进步。
然而,随着事情开始恢复到我所在的世界的一种新的正常状态,这意味着我的一些其他激情的回归,即举起真正沉重的 s#t。虽然知道我终于可以回到他们身边很棒,这几乎是我在勒布朗·詹姆斯在 NBA 打球的时候一直在做的事情,但我不禁想起了我在这次新的努力中在这些追求中所学到的一些东西。*
所以,我想为什么不让“麦克叔叔”分享一些经验来帮助你在这条道路上取得进步。
第一课:“任何方法都会让你成功。坚持就好!”
听着,世界上有成百上千种方法可以让你去你想去的地方。无论是节食和训练计划让你获得足够的提升,成为岩石的替身,还是像《权力的游戏》中的那个巨人一样提升,与学习数据科学相关的目标也是如此。例如,通过了解数据科学获得足够的体面,以便在 FANG 公司找到一份工作。有很多方法可以爬上这座众所周知的山。
"你一定会喜欢那些‘免费’的分时度假介绍,对吗?"
见鬼,只要登录 Instagram、Tik Tok 或 YouTube,你就会发现至少有 10 个人都以不同的方式做到了这一点。当然,可能会有一些方法,你可能会比其他人更喜欢一些方法,一些证据显示多模态方法特别有效,但总的来说它们都有效。然而,每种方法在功效方面的共性都植根于依从性。
合规是一门科学。它在许多结果中扮演着重要的角色,比如健康结果的治疗以及学习,如这里的和这里的和所示。由于影响法规遵从性的因素各不相同,因此没有单一的方法来解决这一问题,关键是要能够识别所有潜在的因素,并提供变通解决方案来充分利用您自己的情况。
请注意,我没有提到任何关于效率或有效性的内容。这是因为你手头的工作可能不会那么高效或有效,尤其是当你有很多事情要做的时候。虽然你的进步速度可能会比别人慢很多,但这仍然是进步。只要进步在发生,你仍然会到达你的目的地。只是需要你一段时间。糟糕,我知道有些人两年计划已经进行了 5 年。重要的是要认识到这一点,接受它,并有弹性度过难关,直到实现目标。
第二课:“你必须赢得进步的权利。”
让我们面对现实吧,在我们内心深处,都有某种程度的“A 型”人格驱使我们想要尽快成功。在另一个世界,这意味着在一两年内尝试获得 315 磅(144 公斤)的卧推,而数据科学等同于尽快获得一份数据分析师/科学家/工程工作。或者,也许想要到达这样一个点,即你可以开始为实际决策、人工智能相关的自动化设计机器学习模型,或者进入具有神经网络的深度假货的古怪世界。
“如果你知道,你就知道”
虽然这种心态令人钦佩,但它也可能是一把双刃剑。值得注意的是,这表现在为了尽可能快地进步而学习的时候忽略了一些细节。这通常发生在达到一个特定的里程碑之后,一旦达到这个里程碑,下一个里程碑就一直在你的脑海中。
重要的是要认识到,达到这一成就等同于能力,而不是才干。如果一个人把这误认为是后者,它只会成为学习进程停滞的催化剂,并在反复暴露于你目前的技能无法解决的困境时最终放弃冒险。
由 Kajetan Sumila 在 Unsplash 上拍摄的原始图像
要变得有能力,需要一个人在彻底的实验和尝试下,通过有意识的应用,持续合理地产生想要的结果。这方面的一个例子是通过使用不同“脏度”级别的各种数据集(包括图像/文本/数字数据集)来重复数据争论过程,或者引入计时元素来亲自查看完成该过程需要多长时间。这些场景是任何与数据相关的职位在招聘过程中经常遇到的。因此,时不时地用同样的方法来学习,看看自己到底在哪里是值得的。
第三课:“当你做过一次,重新开始总是更容易。”
好吧,从零开始做任何事情总是最难的。在什么都不知道和理解甚至最简单的任务的明显困难之间,会既疲惫又令人沮丧,这太糟糕了。所以,毫不奇怪,一旦我们度过了那个“ noobie 阶段,我们就再也不想经历那个阶段了。
嗯,有时候生活会以一种有趣的方式把扳手放进去。无论是工作/学校的事情,需要你立即关注的不可预见的紧迫问题,还是在进一步通知之前身体不适,我们都可能会落后于最初的行动计划,我们的技能也会退步。学习数据科学没有什么不同,只是你不会因为学习而受到身体伤害。嗯,我希望不是。
“这可能是唯一的现实场景,在这个过程中你会受到身体伤害。
在这些时刻最重要的事情是知道你总是可以回到它。当然,你可能最终会意识到你忘记的比你学到的更多,并且不得不做大量的谷歌搜索,比你愿意承认的还要多,但这没关系。你仍然可以回忆起一些对你来说不再陌生的事物。你不能从零开始!把这当成某种长期裁员的一线希望吧。
第四课:“如果你不去追踪它,你不可能取得任何真正的进步!”
没有什么经得起时间考验的不朽之作是通过没有计划地做某事而取得的,而没有确保某些标准得到满足,计划就无法执行。就像那些在每次会议后总是在笔记本上写下他们的进度的人一样,你也需要在你的学习之旅中做同样的事情。虽然这在一定程度上与建立坚持长期计划的责任感有关,但它也可以作为一个日志来观察哪些方面需要改进,以便让你朝着最终目标前进。
在我的情况下,我在日志中记录我在任何给定的一天完成的不同数据科学相关任务的种类,并记录我的表现(即,任务的难易程度、完成时间等)。).在一段合理的时间后,我会回头看看我的日志,看看是否有任何不尽如人意的地方需要改进。如果是这样的话,我可以制定一个行动计划,主要集中在发展薄弱环节,最终成为优势。
鉴于一个机器学习模型只和收集的数据一样好,你自己的学习进度也可以这么说。
第五课:“做傻事是可以的。少做几次就好了。”
我相信,作为任何值得做的冒险的一部分,你最终会在某个时候做一些非常愚蠢的事情。正常情况下,这与你 20 多岁时高估自己的不可战胜感相一致,但在学习的背景下,这可能源于最大化学习进度的强烈愿望。虽然可能看起来不像,但“学习数据科学”等同于在宿醉 AF 或做任何 f#k 这是的时候试图获得一个新的卧推个人记录。*
来自 Pexel 的 Mikhail Nilov 的原始图片
其中最明显的形式是连续长时间(6 个多小时)、深入的疯狂学习会议,或者编写复杂的数据项目,在这些项目中,除了[ 插入最喜欢的品牌 ]能量饮料,你什么都不用做。你知道我说的那些。你开始慢慢从机器人先生变成拉米·马雷克。
现在,我不会说不要这样做,因为有时会需要这样做,或者当期望的最终目标有时会实现时,它们不会实现任何东西。我也不会说它们不令人满意,因为完成马拉松或铁人三项肯定会令人满意。然而,我会质疑,考虑到权衡利弊,所有这些真的有必要吗?难道我们不能在不通过冥府之门的情况下接近这一切,最终得到同样的结果吗?
当然可以。这只是一个关于它的策略和策略的问题。这意味着建立有用的习惯/行为,适当的项目规划,以及关注生产力和健康的指导方针。其中包括:
- 设定 90 分钟的上限来完成任何给定的任务,然后在任务之间留出 15 分钟的间隔
- 制定一个可行的粗略计划,并保持保守
- 通过关注每项任务后的感受,将累积的精神压力分散到更长的时间里。如果你觉得因为精疲力竭而需要长时间休息,那就好好休息一下吧!
- 优先考虑完成工作的质量,而不是完成工作的数量。更多并不总是更好;有时候,这意味着未来的自己需要做更多的事情。
正如一位世界著名的脊椎专家曾经说过的,“在事情发生之前,你只能做几次这样的事情,所以要选择什么时候做,什么时候不做”。
这就是了。
我作为一个傻瓜的五个简单的教训被用在了这个新的尝试中。当然还有很多。然而,我觉得这些是最切中要害的。
那么,我的数据科学学习伙伴们,你们呢?你从自己身上学到了什么,你用在了学习这个领域的其他激情上?
欢迎在下面评论,让我知道你的想法。
如果你对联系感兴趣,请联系我的 LinkedIn。
感谢阅读,并期待一些其他有趣的东西来。
五种主要的数据项目类型
观点—您将遇到的典型数据项目
从事数据领域的工作,有哪些典型的项目?
在我从事数据分析和大数据领域的工作期间,我反复遇到了五种基本类型的项目。我想在这篇文章中介绍这些,并描述它们的特点。
数据存储和管道
在对数据做任何事情之前,您必须将数据从源系统转移到目标系统,例如数据仓库或湖。在这里,大多数 ETL 或 ELT 项目是必要的。不能低估这些数据处理或数据管道,因为您必须考虑:
- 可用性:源系统何时可用?你必须考虑维护周期、停机时间等。
- Load Times :从源系统加载数据需要多长时间,我的进程在满负荷的情况下访问源系统需要多长时间?
- 不同的数据结构:在大数据的新世界中,基于列的非关系数据库和数据仓库正在兴起。
- 业务脉络:除了这些技术点,你还应该对源系统背后的一般业务有一点了解。
此外,构建容错且可监控的流程当然也很重要。
数据质量测量流程—作者提供的图片
数据分析和科学
这种类型的项目通常以报告、仪表板或机器学习服务结束。在这里,分析师或科学家比数据工程师更重要。除了较小的 PoC,还可能存在较大的项目。尤其是当最初的数据分析必须自动化和标准化时,最初的数据分析可能是在第一步通过 Jupyter Notebook 进行的。然后,这些项目就像其他软件项目一样,在一个已建立的、可扩展的平台上高效地展开。
集成的数据湖和分析平台—作者图片
数据应用
这里,重点是首先生成数据的系统。这里的相关问题是,例如,如何提高源系统中主数据的质量。因为大家都知道数据进来了,马上又出来了。BI 和分析部门还应与 IT 或系统的产品所有者密切合作。例如,可以通过对系统进行调整来纠正缺失的信息。例如,如果我需要来自商店系统的元信息,这可以在下一个开发周期中考虑。
安全性、访问和监控
除了这三种类型的项目之外,对我来说还有另一种数据项目类型,那就是与系统上的安全操作和安全性有关的一切。对我来说,这里必须考虑以下关键领域:
- 数据保护:例如,我如何保护 GDPR 数据?
- 监控:我的系统在工作吗,谁有权限?
- 数据安全:是否有固定的暂存区,是否有备份?
- 成本监控:比如有没有异常?
无论如何,这些都是每个数据平台都需要考虑的任务,而且通常规模更大,作为单独的项目来执行。然而,对我来说,最重要的一点是能够在一个安全可信的环境中执行数据计划。而且也是为了避免诸如不遵守 GDPR 的处罚。
成本优化
系统上的大量数据和大量用户需要花钱。通过迁移到云,这些通常可以减少,但前提是应用程序得到有效利用。例如,这一领域的项目可以是:
- 成本监控
- 数据结构和查询的优化
- 数据存储和归档的优化
特别是对于像 Google BigQuery AWS Redshift 或 Snowflake 这样的新系统,以嵌套形式存储数据并定期归档数据是有意义的。还建议为自助 BI 工具设置成本监控,以便识别用户和可能的反模式。
摘要
在我的职业生涯中,我经常遇到前面提到的五种数据项目类型。他们每个人都有自己独特的挑战和特点。因此,人们必须考虑它们,以便为它们各自的计划和最终结果找到完美的数据项目类型。
数据分析师的十个基本 Excel 函数
您不需要为每个数据任务都使用 Python
虽然 Python 是数据科学领域的主导工具,但 Excel 是一种方便易用的方法来执行分析或向利益相关者显示信息。由于 Microsoft Excel 在商业世界中广泛使用,并且界面对于许多没有数据背景的人来说是熟悉的,因此它对于需要与企业中的其他部门共享的分析和报告非常有用。
在本文中,我们将探讨十个 Excel 函数,以获得软件的更多功能,并在 Excel 中快速执行常见的数据分析任务。
计数空白
原始数据可能是杂乱的,有时它可能包含丢失的值,尤其是当这些数据是在现实世界中收集的时候。在 Python 中,我们可以使用 isna()之类的方法来检测丢失的值。但是,在 Excel 中使用 COUNTBLANK 函数也可以做到这一点。
COUNTBLANK 将计算给定范围内空白单元格的数量。
使用 COUNTBLANK 函数检查缺失值。图片作者。
该 Excel 函数的公式为:
=COUNTBLANK(范围)
苏米夫斯
最著名和最基本的 Excel 函数之一是 SUM 函数。有时我们可能希望使用 SUM,但是也使用一个标准将单元格从求和中排除。这就是 SUMIFS 的用武之地。
SUMIFS 允许我们对给定范围内的值求和,但只对符合给定条件的值求和。根据需要,可以为该函数提供任意多的标准。
使用 SUMIFS 函数计算不同地点的雇员数。图片作者。
该 Excel 函数的公式为:
=SUMIFS(sum_range,criteria_range1,criteria1,…)
等级
RANK 函数可用于返回某个数值在与其他数值列表进行比较时的排名。在数据分析中,排序对于了解特定值在有序数组中的位置非常重要。还有一个类似的函数 PERCENTRANK,它以数据集范围的百分比形式返回排名。
需要注意的是,如果在给定的列表或数组中找不到值,Excel 将返回#N/A 错误。对于 PERCENTRANK 来说,情况并非如此。
使用 RANK 函数按员工数量对地点进行排名。图片作者。
该 Excel 函数的公式为:
=RANK(数字,列表)
纵向查找函数
VLOOKUP 是任何数据分析师都应该知道的最重要的功能之一。它可以用来检索或查找垂直排列的表格中的数据。这非常有用,因为它可以用来自动查找另一个电子表格中的数据,只要每行都有一个 ID。
表的 ID 列必须是第一列。VLOOKUP 函数中的第三个参数可用于引用包含要检索的数据的列。需要注意的是,这个参数在 Excel 中是从 1 开始的。这意味着值 2 将得到第 2 列,值 3 将得到第 3 列,依此类推。这与 Python 中的列表索引不同,后者是基于 0 的。
VLOOKUP 函数中的另外两个参数指的是查找值(或正在检索的行的 ID)和表本身的范围。
使用 VLOOKUP 函数查找不同位置的数据。图片作者。
该 Excel 函数的公式为:
=VLOOKUP(查找值,表数组,列索引号)
IFERROR
如果您要向公司中的其他人展示 Excel 电子表格,那么当函数中出现错误时,在单元格中使用默认值会很有用。当其他用户不理解错误的含义时,或者当计算中出现错误(如默认为 0)时单元格的值已知时,这可能特别有用。
IFERROR 函数可以做到这一点。这个函数只接受两个参数,第一个是函数,第二个是函数抛出错误时的默认值。如果函数没有抛出错误,那么值将正常输出。
使用 IFERROR 函数处理 Excel 错误。图片作者。
该 Excel 函数的公式为:
=IFERROR(值,值 _if_error)
天
如果您曾经处理过与时间相关的数据,您会知道有几个关键的计算会在您的工作中重复出现。其中之一是计算两个日期之间的天数。在 Excel 中,我们可以用 DAYS 函数来实现这一点。
DAYS 函数将两个日期作为参数,并以整数形式返回它们之间的天数。
这个函数有用的一个场景是计算订购产品和交付产品之间的时间。对于销售产品的企业来说,这是一个重要的指标,所以 Excel 提供了一个简单的方法来计算它是一件好事。
使用天数函数计算交付产品的天数。图片作者。
该 Excel 函数的公式为:
=天数(结束日期,开始日期)
MAXIFS
在商业中,找到一个变量的最大值是非常重要的。从知道一年中最忙的一天到一家企业一天中获得的最大利润——计算最大利润有很多原因。
有时,您可能只想计算数据子集的最大值。在这种情况下,您可以使用 MAXIFS 函数对您想要取最大值的数据进行约束。
在下面的例子中,我们使用 MAXIFS 来查找交付每种产品的最大天数。约束被放置在数据集的每一行中的产品上。
使用 MAXIFS 函数获得每个产品的最大交货时间。图片作者。
该 Excel 函数的公式为:
=MAXIFS(max_range,criteria_range_1,criteria_1,…)
平均寿命
前面我们探讨了使用 SUMIFS 来过滤数据的总和。我们还研究了 MAXIFS 来做同样的事情,但是使用了最大值。到目前为止,您可能已经发现 Excel 中可以使用许多不同的 IF 函数。
其他一些有用的 IF 函数包括 COUNTIFS、MINIFS 和普通的 IF 函数。一个经常出现的函数是 AVERAGEIFS 函数,它用于计算平均值。
在下面的例子中,我们使用 AVERAGEIFS 函数来计算每个产品的平均交付时间。
使用 AVERAGEIFS 函数获得每个产品的平均交付时间。图片作者。
该 Excel 函数的公式为:
=AVERAGEIFS(average_range,criteria_range_1,criteria_1,…)
比赛
有时,了解数据值出现的特定列或行会很有用。我们将在文章的后面查看一个用例,但是首先,我们将介绍允许我们这样做的函数。
MATCH 函数用于确定一个值在给定数组中的位置。重要的是要记住这个结果是相对于数组的开始的,所以结果 4 不一定意味着你要找的值在电子表格的第 4 列或第 4 行;它将位于给定范围的第四个位置。
使用 MATCH 函数获取数据集中的特定行。图片作者。
该 Excel 函数的公式为:
=MATCH(值,数组)
指数
INDEX 是一个通常与前面的 MATCH 函数一起使用的函数。它们可以一起用于根据给定的标准获取查找表中的值,类似于 VLOOKUP 函数。但是,在单一查找函数失败的某些情况下,可以使用这两个函数,例如当查找值不在范围的第一行/列中时。
INDEX 函数本身用于返回给定行号和索引号的单元格的值。
在下面的例子中,我们可以看到 MATCH 函数用于获取产品在 11 天内交付的行,然后 INDEX 函数用于获取该行的产品描述。
结合匹配和索引功能进行查找。图片作者。
该 Excel 函数的公式为:
=INDEX(数组,行号,列号)
结论
现在你知道了!使用该软件进行数据分析的人必须知道的十个 Excel 函数。如果您在 Excel 中进行大量工作,这十个功能将会非常频繁地出现,既然您知道如何执行常见任务,就没有理由不使用该软件。
虽然您将很好地利用本文中提到的所有函数,但我建议您密切关注匹配和索引的配对。这是 Excel 世界中极其常见的函数配对,只要稍加练习就很容易做到。
如果匹配/索引配对对您来说很难使用,那么从 VLOOKUP 开始,并理解该功能的不同用例。
您认为对于 Microsoft Excel 来说,还有哪些尚未提到的功能是必须了解的?请在下面的评论中提及它们。
Python 中五个必须知道的字符串方法
使用 PYTHON 进行实际数据分析
完美地处理数据分析项目中的字符串
奥马尔·弗洛雷斯在 Unsplash 上拍摄的照片
我遇到的最常见的数据类型是 String,在 Python 中用 str 表示。Python 提供了 30 多个内置函数⚡️来操作字符串,让我们的生活变得更简单。了解这些函数不仅有助于数据分析,还能保持代码的简单性。通过这个故事,我将带你了解 5 个必须知道的字符串操作方法,并分享一些移动中的技巧💡来弹奏琴弦。
这个故事的要点是—
📌你将掌握五种必须知道的字符串操作方法
📌获得 30 多个字符串方法的单幅图片说明
📌包含所有字符串方法的 Jupyter-notebook
字符串是我所有项目中最常见的数据类型。知道这些字符串操作方法,总是帮助我加快我的分析。
在深入之前,我先告诉你一个字符串最简单的定义。
"在 Python 中,用单引号或双引号括起来的都是字符串."
字符串是一个字符序列。字符可以是任何东西——数字、字母、符号和空格。
💡单引号还是双引号?
当字符串中没有单引号字符时,两者的行为完全相同。这张图片更好地解释了这个场景。
Python 中字符串的单引号和双引号(图片由作者提供)
字符串表示数据中的文本,因此可以是任意长度。可以对字符串执行各种操作,例如查找字符串中的特定字符、替换文本中的单词、改变字符串的大小写(例如小写——大写)、拆分字符串或连接它们以获得新字符串。
让我们开始吧…
Python 中的字符串格式()
可以使用 format() 方法生成格式化的输出。它允许使用简单的占位符进行格式化。很多时候,有一种情况,你需要格式化一个特定的值,并把它插入到字符串中。
下面是这个场景的经典案例,打印一个输出字符串,其中包含来自数据分析的一些数字和单词。在这种情况下,使用 format() 方法将数字和单词格式化并插入到输出字符串中。
Python 中字符串格式()的经典案例(图片由作者提供)
如上例所示,.format()
中提到的变量(标有绿色方块)包含一些值,这些值将被插入到 print 语句的占位符中,以完成输出字符串。在 Python 中,占位符由花括号{} 表示。
现在,让我告诉你如何在你的分析项目中使用 fformat()方法。下面是实现 format() 方法的 4 种方法。
以上所有实现 format() 方法的方式的输出都是一样的。你可以在下图中查看。
实现 String format()方法的四种方式(图片由作者提供)
尽管如此,寻找💡更简单的实现格式()?
那你应该去 f 弦。它也被称为格式的 字符串文字。这种 f 字符串在要格式化的字符串开头有一个字母***f***
,在字符串中有多个占位符***{}***
。看看下面,
上例的简化视图如下图所示。
Python 中的 f 字符串(图片由作者提供)
Python 中的字符串替换()
在我的一个项目中,当我探索 google 评论数据时,我想用默认字符串替换评论中的一些垃圾文本。我利用str.replace()
来保持代码的整洁。
Python 中的字符串是不可变的 →因此原始字符串不能被改变。因此,所有方法都会生成字符串的副本,对其执行操作并将其作为输出返回。
语法来了——
str.replace(old_substring, new_substring)
这个str.replace()
返回原始字符串的副本,其中old_substring
被替换为 my new_subsstring
。让我用一个例子来说明这一点。
Python 中的字符串替换()
简单?哦,等等,你注意到了?原始字符串中的所有 old _ substrings 都被替换为 new_substring。如果,💡我只想改变原字符串中 old_substring 的前两次出现?
然后是第三个也是可选的参数str.replace()
。它指定了用新的子串替换旧的子串的次数
用 count 替换()字符串(图片由作者提供)
这就是你用这个replace()
方法能做的全部。
Python 中的字符串连接()
在浏览 google reviews 数据时,我想将餐馆、地区、城市和邮政编码的名称连接起来,形成一个完整的地址作为单个字符串。方法join()
在那里帮助我。它很快将一个字符串连接到另一个字符串,形成预期的输出。
这个方法的语法非常简单:separator.join(arg)
字符串连接()(图片由作者提供)
正如您在这里看到的,方法join()
只接受一个参数,并且它必须是,这意味着它可以是一个字符串、一个列表或一个元组。分隔符可以是逗号、空格、冒号,甚至是其他字符串。
再看一下下面的例子,
带有列表的字符串连接()
这里每个字符串都有很好的定义,简单地将一个字符串列表传递给join()
。让我给你展示一下,在熊猫的数据框架中事情是如何运作的。这是另一个例子,
Pandas 数据帧中的字符串连接()
Woohoo!!
所有的列合并成一列,我得到了餐馆的完整地址。在每一行中,所有单元格都用逗号和空格作为分隔符连接在一起。
在上面的例子中,还可以看到一个经典案例💡如何将代码编写成多行,以及如何使用函数。
Python 中的字符串 split()
方法split()
与方法join()
完全相反。与join()
不同,split()在指定的分隔符或分隔符上分隔字符串。
在 split()中提到分隔符也是可选的。因此,如果你没有提到任何分隔符,默认的分隔符是空格,字符串将被分割在每个空格上。作为输出,您将得到一个分隔字符串的列表。
有了这个背景,你可能已经考虑过语法了。any_string.split(separator, number_of_splits)
在语法中可以看到,split()还接受另一个可选的参数数目的拆分。因此,如果设置为 1,意味着将返回两个分开的字符串。
一个例子更好地解释了这一点。
字符串拆分()(图片由作者提供)
让我们来看另一个例子,在 split()中提到了两个可选参数
带所有选项的字符串拆分()
如上图所示,在*string2*
上执行了 2 次分割。第一次分割在分隔符#
第一次出现时进行,第二次分割在#
第二次出现时进行。在处理文本数据时,Split()是一个非常方便的工具。
为了新冠肺炎数据分析项目,我抓取了一个流行的网页来收集所有的数据。不出所料,我在国名的开头和结尾看到了一些不需要的字符。我用replace()
去掉了这些不需要的字符,但是字符串开头和结尾的随机数量的空格怎么办?
【strip()来救我了!💡
strip()可以被视为 split()的一种特殊情况,专门用于从字符串的开头和结尾删除空格。strip()移除字符串开头和结尾的空格。
strip()(图片由作者提供)
但是,如果您希望只删除字符串开头或结尾的空格,那么 strip()又有两个子类型— lstrip()
和rstrip()
字符串带()子类型(图片由作者提供)
您仍然可以尝试结合 split()、strip()和 replace()来进行各种数据转换,并获得所需的结果。愉快的实验。
让我们使用find()
方法在给定的字符串中寻找一些特定的单词和数字。
Python 中的字符串 find()
当我自动化我的第一个数据分析项目时,我曾经得到一个字符串作为输出,并且我需要在这个字符串中找到一个特定单词的位置。就在那个时候,我第一次使用了find()
这个方法。
由于该方法的目的是在主字符串中搜索特定的子字符串并返回其索引,find()
接受 1 个强制参数和 2 个可选参数。它带有语法:
string.find(substring, start_position, end_position)
字符串查找()(图片由作者提供)
上图清楚地解释了方法find()
如何返回主字符串中子字符串第一次出现的索引。
但是,如果子字符串不在主字符串中,或者不在给定的起始和结束位置范围内,该怎么办呢?
别担心!!!见下图。💡
找不到子字符串时(作者图片)
如果在给定的主字符串中没有找到子字符串,Python 返回 -1 。
仅此而已!!在我所有的项目中,我发现这 5 个字符串方法最有用。掌握这些肯定能加快你的数据分析速度。
_________ _ _ _ 图像比语言更有说服力 _ _ _ _ _ _ _ _ _
📌是时候用 30+ 字符串方法生成单个图像了。通过这张图片,您可以了解 Python 中的所有字符串方法,并可以作为快速参考。
一张图中的所有字符串方法(图片由作者提供)
📌如你所见,这些是我的笔记本的真实快照。
💡有兴趣了解更多关于数据争论的知识吗??这里有一个关于它的快速阅读。
* *
长话短说,
通过我的故事,我向你介绍了五个必须知道的字符串方法。掌握了这些方法,我已经使我的数据分析更快更简单,希望它也能帮助你。
一如既往,我乐于接受反馈,并了解您在项目中使用的其他更快的数据分析方法。
感谢您的时间和阅读!
📚在这里看看我关于数据分析的其他文章。
五个数字函数为您节省时间
如何堆叠你的数组水平和垂直,找到唯一的值,分裂你的数组和一些更有效地使用 Numpy 的技巧。
泰勒·尼克斯在 Unsplash拍摄的照片
Numpy 可以说是数据科学中使用最多的库,正好和熊猫一脉相承。这是您在每个数据科学项目中导入的第一个库,根据我的经验,只需要知道一些函数,就可以用最少的搜索来快速修改您的数组,这非常有帮助。
import numpy as np
因此,打开你的 Jupyter 笔记本和你最喜欢的笔记应用,在你阅读这篇文章的时候记下这些功能。它们将在你未来的项目中派上用场。
我们走吧!👇
制作特殊阵列
在这个类别中,我包含了三个 numpy 函数:
- 制作一个零数组:
np.zeros((2, 3)) # make a 2x3 matrix of zeroes
- 制作一个 1 的数组:
np.ones((2,3))
而且,
- 做一个身份的方阵:
*# identity matrix*
np.eye(3, 3, dtype=int)
特殊 numpy 数组函数
在数组中查找唯一值
要查找并获得数组中所有唯一值的列表,只需记住一个简单的函数:
np.unique(arr) # get unique values in arr
numpy 数组中的唯一值
很方便,不是吗?
垂直和水平拆分数组
将一个数组分成相等的两部分对于随机抽取您正在处理的数据的一部分非常有用。
我们首先定义一个简单的数组:
数组定义
然后,我们把它分开:
np.hspit(arr, (tuple of columns to split with))
numpy 数组分裂
同样,您也可以通过 vsplit 函数进行垂直分割。
np.vsplit(arr, 5)
寻找最小值和最大值
考虑这样一个数组:
示例 numpy 数组
然后,我们可以通过以下方式获得最大值和最小值:
numpy 数组最大值、最小值
如果您输入axis = 0
,它将按行计算最大值和最小值,而不是按列。
堆叠阵列
一个在另一个的上面或者一个在另一个的旁边,numpy 具有各种堆叠两个或更多阵列的功能。
让我们先定义两个简单的数组:
两个 numpy 阵列
然后,我们可以通过以下方式将它们水平堆叠:
np.hstack((arr, arr2))
阵列的水平堆叠
同样,对于垂直堆叠,您可以这样做:
np.vstack((arr, arr2))
阵列的垂直堆叠
结束…
下一步是什么?你应该继续记忆这些方法吗?不尽然,因为一旦你开始在下一个项目中的一些数据上练习它们,你会在适当的时候自动记住它们。不需要额外的努力。
既然您已经知道了这种很酷的 numpy 函数的存在,我建议您继续自己尝试它们。也许你会发现一些我在这篇文章中没有探究的巧妙的小技巧?一切都归结于一些练习。它可以是奇妙的,也很有趣!
独自踏上数据科学之旅是艰难的。我分享我从这些每周文章中学到的一些小知识。跟我来让我们一起让学习变得有趣!😃
此外,这里是我所有数据科学故事的代码库。快乐学习!⭐️
这是我的另一篇文章,你可能想看看:
</26-datasets-for-your-data-science-projects-658601590a4c>
此外,请随意访问⭐️,并跟随这个 repo 访问我制作的完整 Numpy Cheatsheet 和我将来会包含的其他很酷的 Python 概念。快乐阅读!