如何让你的数据科学代码评审更好
原文:https://towardsdatascience.com/how-to-make-your-data-science-code-reviews-better-13ac090560d2
从主持代码评审中吸取的经验教训
Artem Sapegin 在 Unsplash 上拍摄的照片
对于许多开发人员来说,代码评审可能是有压力的,尤其是如果你以前没有做过的话。反过来,它们在数据科学中越来越常见,尤其是当我们开始与更多面向软件的个人合作时。在不同的数据科学和工程团队中工作,让我在审查其他人的工作时,看到了哪些工作得好,哪些工作得不好。当然,并不是每个团队都以同样的方式进行代码评审,但是我想分享一些共同的经验以及我如何从这些评审中获得价值。
开发标准实践
无论是编程风格指南还是命名约定,您都需要为您的团队开发一套标准的编码实践。制定这一标准并经常引用它将有助于您的数据科学家符合预期。
我在我工作过的团队中发现,如果没有为人们制定的实践标准,每个人都会创建自己的标准,每个人的编码风格都是不同的。我不是说我们不能有自己的风格;看到人们编码方式的差异是很好的,但是命名约定和变量定义等项目可能会有很大的不同。因此,制定一个标准可以提供一些一致性,使代码更具可读性和可维护性。
当我作为团队领导专注于工具和 ML 实践时,我花了一个月的时间为我们的团队开发标准实践。这些实践包括所有我们期望的命名约定,创建功能性和面向对象代码的编码风格指南,以及代码评审的过程。这组文档被我们的团队很好地使用,并且经常被新的数据科学家引用。这是如何发展的基本原则。将这些文档视为您入职的起点和经验丰富的成员的参考。
查看编码标准的另一个原因包括对您将使用的编码范例的类型进行描述。我经常看到数据科学家更倾向于脚本或函数式编程。函数式编程有助于数据科学,也是我经常看到的团队采用的范例。对于我合作过的数据科学团队来说尤其如此,他们知道编码的基础,但不是软件开发人员。
总结您的更改
在数据科学家入职并开始开发他们的代码后,他们打开拉请求以批准他们的更改和添加。当我在以前的角色中主持代码审查时,我首先要求数据科学家总结他们的变化。这听起来可能有点奇怪,因为不是每个团队都这样做,但是概述你的变化是一个很好的反思工具。
当你坐下来打开你的拉请求时,花几分钟写一下你的代码。首先,您应该记录您对代码的添加、删除和更改。这个拉取请求解决了什么问题,你是如何解决的?如果您自己都不能回答这些问题,那么您的代码审查人员应该如何回答呢?
给自己一些思考的时间来总结你的变更,这有助于评审者理解你的代码,并给你时间来理解你在这个拉请求中所做的事情。通常,花几分钟时间反思我的工作可以让我在进行代码评审之前看到我可以做出的错误或更改。
这种类型的文档有帮助的另一个原因是为了可追溯性。例如,如果一位经理或客户问你六个月以后,你什么时候以及为什么做出了改变,你能回答吗?大概不会。彻底跟踪您的存储库中已经发生的变更,并记录这些变更为什么会发生,这为您回顾过去提供了一个很好的方法。当然,你永远不知道接下来谁会需要查看这些变化,或者为什么。因此,请准备好手头的文档。
分享知识和提出问题
您的代码审查可能脱机或正在开会;这取决于球队如何运行他们的。但无论形式如何,这都是分享知识和提问的时间。这是您向其他数据科学家、软件工程师和其他人学习的时间。当有人对你的代码发表评论时,确保你理解他们为什么留下评论。
- 他们会推荐一个 bug 补丁吗?
- 他们是否陈述了要遵循的最佳实践?
- 他们有没有指出一种更好的方式来格式化你的代码或者重新设计一个函数?
- 你的工作中有新的算法、技术或数据需要考虑吗?
不管他们提出了什么,让他们澄清他们的评论,这样你就可以从中学习。一旦你理解了你的评审者在要求什么,你需要知道这是否是批准拉取请求所必需的,或者是不需要实现的“思考的食粮”类型的变更。我经常看到代码评审者分享一些想法,这些想法不需要被实现,但是在某种程度上是有教育意义的,可以和你分享技术和新的想法。
不要浪费时间。相反,从中学到尽可能多的东西,并在你的下一个任务中使用这些知识。
不要独占所有权
我喜欢代码审查以及与其他数据科学家和软件工程师合作的部分是当人们愿意接受其他人添加到他们工作中的时候。我不认为代码应该由公司中开发它的人“拥有”。代码不是你的;这是公司,所以不要霸占所有权或领土。
每个人都应该觉得他们可以在代码库的不同部分工作,并互相学习。总有一些东西可以从研究你的代码的其他人那里学到,并且让更多的人熟悉代码库。例如,如果只有一个人拥有代码,然后他们离开了,现在你要花更多的时间去理解他们离开后的工作。当有人在那里和你一起工作,并教你他们当时为什么做出编码决策时,学习起来更容易。
当讨论 ML 算法的设计决策时,尽可能从你的队友那里学习代码是至关重要的。当您查看这些代码时,您可以向他们询问他们所创建的特性,他们使用什么数据分析来得出结论,他们如何检查输出的指标,等等。举行这些知识传授会议并向他人学习是有益的。所以不要强占所有权;相反,注重协作和创新。
成为代码评审员
在我工作过的团队中,并不是每个人都是代码审查者。通常,这是由高级数据科学家和软件工程师来完成的。虽然我可以理解为什么让一个更资深的成员来评审你的代码是有帮助的,但是我认为至少有一个中级或初级人员来评审代码也是很好的。让他们审查其他人的代码,并学会给出可靠的反馈。
在以前的工作中,我经常邀请一两个低年级学生加入我们的评审。我们的评审是在一个会议上进行的,个人可以亲自讨论他们的结果和代码。在一次会议结束时,一名初级数据科学家找到我,告诉我他们看到其他人编写代码感到很欣慰。这让他们意识到他们知道的比他们想象的要多,并让他们看到其他人的代码是如何实现的。结果,随着时间的推移,这个人开始对自己的编码能力更加自信,并开始根据他的学习给出反馈。
向从未做过评论的人公开你的评论是一次很好的学习经历。不要觉得他们不能做出贡献,因为他们比你新。每个人都需要从某个地方开始,越快越好。
最后的想法
代码审查可能是一种紧张的,有时甚至是可怕的经历,但是它们不一定是这样的。学会与你的团队合作开发一个安全开放的环境,允许协作和知识共享。
- 为你的团队开发标准实践。这为经验丰富的团队成员提供了很好的参考,并允许新人更快入职。
- 总结你的变化。花时间反思你的工作可以帮助你发现错误或你可以做出的改变。这也让其他人更容易知道从你的代码中能得到什么。
- 分享知识,提出问题。这是你学习的时间!与你的队友分享知识和想法,并乐于提问。确保你澄清了你不清楚的评论。
- **不要霸占所有权。**代码不应该属于一个人。相反,每个人都应该感觉到他们可以学习并为代码库的不同部分做出贡献。培养创新和协作的文化。
- **成为一名代码评审员。**无论你是初级、中级还是高级,你都应该参与点评。代码评审是建立信心、学习和发展反馈能力的好方法。
什么帮助你改进了代码评审?你有什么经验教训想要分享吗?
感谢阅读!我希望你喜欢阅读我所学到的东西。如果你愿意,你可以通过使用这个链接成为一个媒介会员来支持我的写作。
如何让你的数据科学项目脱颖而出
原文:https://towardsdatascience.com/how-to-make-your-data-science-projects-stand-out-d9e0eb6bb3df
增加收入以显示业务影响
数据科学家的工作竞争越来越激烈,能够从众多申请者中脱颖而出将增加你被录用的机会。数据科学项目组合是展示你的知识的好方法,特别是对于有抱负的数据科学家,但是招聘经理如何知道这个项目的价值呢?添加收入估计可以帮助您的项目脱颖而出,因为它向招聘经理展示了您知道如何将数据科学成果与业务影响联系起来。今天,我想讨论如何评估数据科学项目的收入影响。
建立基线
第一步是建立基线收入。您使用的输入将因公司的业务模式而异。一种方法是使用漏斗分析来确定收入计算的最佳输入。
下面是一家电子商务公司的简单收入计算。
示例 1 作者创建的电子商务收入计算
我假设网站每月有 100,000 个访问者(单元格 B1)。如果你的项目使用真实公司的数据,试着为你的收入计算找到实际的数字,使它更加真实。比如我用的美国电商转化率 3% ( cell B2)。订单数量(单元格 B3)的计算方法是 100,000 个访问者(单元格 B1)乘以 3%的转化率(单元格 B2)。
将结果与业务影响联系起来
现在,让我们将您的数据科学项目与业务影响联系起来。提高普通 KPI(如转换率或流失率)的项目很容易联系起来,因为它们对收入有直接影响。
然而,这种关系并不总是简单明了的。例如,情感分析项目如何帮助提高收入?情绪分析有助于公司了解客户投诉,从而提高客户保留率,进而增加终身收入。
挑战自我,弄清楚您的数据科学项目如何帮助提高业务 KPI,以将影响联系起来。
计算收入
假设你的数据科学项目将转化率从 3%提高到了 4%。这意味着每月收入增加了 50,000 美元,增幅为 33%。显示你的项目增加了 1%的转化率不会得到太多的关注,但增加 33%的收入肯定会脱颖而出。
示例 2 作者创建的电子商务收入计算
让我们尝试另一个产品推荐项目的例子,该项目增加了每个订单平均购买的两件商品。下面,我们将第 4 行到第 6 行中的输入添加到收入计算中,以估计影响。
示例 3 作者创建的电子商务收入计算
假设平均订单值为 50 美元(单元格 B6 ),计算方法是每个订单 5 件商品(单元格 B4 ),每件商品 10 美元(单元格 B5 ),每个订单再增加 2 件商品将使平均订单值达到 70 美元。与第一个示例类似,显示您的项目将每个订单的平均项目从 5 个增加到 7 个,不如添加您的项目将每月收入增加 60,000 美元,即增加 40%。
最终想法
我已经展示了几个如何将数据科学项目结果与收入影响联系起来的示例,但投入会因项目而异。为您的收入计算找到合适的输入是展示您知道如何将数据科学结果与业务绩效联系起来的另一种方式。在讨论为您的投资组合创建哪些数据科学项目时,请考虑结果如何与收入相关联,以帮助您决定最具业务影响力的项目。
你可能也会喜欢…
https://medium.datadriveninvestor.com/how-data-scientists-can-develop-business-acumen-870eb55866e6
如何向公众展示你的模型
原文:https://towardsdatascience.com/how-to-make-your-models-available-to-the-public-be782dcb9942
解释如何使用 Docker、Flask 和 Gunicorn 在线部署您的模型
MLOps 作为交叉文氏图[ CC BY-SA 4.0 ]
介绍
端到端的机器学习解决方案是将人工智能带入生产并使其可供大众消费和使用的重要方式。但今天,大多数人工智能从业者只是简单地做预处理,训练,评估和调优阶段,并将剩下的部分留给 DevOps 工程师。
因此,一个名为 MLOps 的新开发领域已经成为主流。重点已经从简单的培训和评估转移到将信息技术引入并整合到生产流程中。
在个人层面上,知道如何将你的模型公之于众是人工智能从业者技能组合中的一个重要工具。
在本文中,我们将探索如何使用 Keras、Flask、Gunicorn 和 Docker 以简单高效的方式执行 MLOps 循环的一小部分。
如果你想跳过并直接进入代码,点击这里进入 GitHub 库。
本教程涵盖了哪些内容?
- 使用
Keras
及其现成组件创建一个定制模型 - 准备推理管道
- 开发一个简单的
Flask
应用程序来公开用于推理的模型 - 使用
Gunicorn
定义一个Dockerfile
- 建立我们的形象
- 定义一个简单的 Github Actions 工作流,在每次将图像推送到存储库时构建图像
1)使用 Keras 创建自定义模型
例如,我们将使用 Keras Functional API 和 ImageNet 上预训练的keras.applications
的现成MobileNetV2
模型创建一个简单的模型。
导入标题
本教程需要tensorflow
、keras
、Flask
、PIL
和os
。如果使用虚拟环境,您可以使用下面的requirements.txt
文件来准备您的 env。
tensorflow
:用于矩阵运算和 keras 后端keras
:用于高级深度学习建模 API,获取预训练模型Flask
:用于构建简单的 API 进行推理PIL
:用于处理图像os
:用于设置环境变量
import tensorflow **as** tf
from tensorflow import keras
from flask import Flask
from flask import request**,** jsonify
from PIL import Image
import os
设置选项
由于 GPU 是一种很难获得的资源,我们设置了一个 Tensorflow 标志,以便首先使任何 CUDA 设备不可见。如果你能在 GPU 上运行你的容器,请随意跳过这一行。
os**.**environ**[**'CUDA_VISIBLE_DEVICES'**]** **=** '-1'
模型定义
这个模型是使用 Keras Functional API 制作的。我们用一个简单的keras.Input
来接受任何大小的彩色(RGB)图像。
输入通过以下层传递:
keras.layers.Resizing
:用于将图像张量大小调整为 224x224x3 张量。keras.layers.Rescaling
:用于将图像张量值从[0,255]范围重新缩放到[0,1]范围。keras.applications.MobileNetV2
:用于从 Keras 导入 MobileNetV2 实例(在 ImageNet 上预训练)。
image_input **=** keras**.**Input**(**shape**=(None,None,**3**))**x **=** keras**.**layers**.**Resizing**(**height**=**224**,** width**=**224**,** interpolation**=**'lanczos3'**,** crop_to_aspect_ratio**=False)(**image_input**)**x **=** keras**.**layers**.**Rescaling**(**scale**=**1.**/**255**,** offset**=**0.0**)(**x**)**mobilenet **=** keras**.**applications**.**MobileNetV2**(**
alpha**=**1.0**,**
include_top**=True,**
weights**=**"imagenet"**,**
input_tensor**=**image_input**,**
classes**=**1000**,**
classifier_activation**=**"softmax"
**)**model_output **=** mobilenet**(**x**)**model **=** keras**.**Model**(**inputs**=**image_input**,** outputs**=**model_output**)**
需求文件
Gunicorn
用于将 API 部署到多个工作线程上,以增加计算消耗为代价降低延迟。使用 Gunicorn 是因为它实现了 WSGI。在生产环境中,像 NGINX 或 Apache Web Server 这样的前端服务器用于托管静态网页和负载平衡器,Gunicorn 在该层后面运行以实现功能。
Flask**==**2.0**.**3
Pillow**==**9.2**.**0
tensorflow**==**2.9**.**1
gunicorn**==**20.1**.**0
2)准备推理管道
我们定义了一个简单的函数,它接受一个tf.Tensor
,并在模型中运行它,以返回一个最终的前 5 名预测字典结果。
推理功能
使用之前准备好的函数来推断作为tf.Tensor
接受的图像。然后提取张量的numpy
值,以获得每个类别的所有置信度得分。
这个 numpy 数组然后被传递到keras.applications.imagenet_utils.decode_predictions
以获得前 5 个预测。
**def** **inference(**image**:** tf**.**Tensor**):**
y **=** model**(**image**).**numpy**()**
preds **=** keras**.**applications**.**imagenet_utils**.**decode_predictions**(**y**,** top**=**5**)**
result **=** **{**i**[**1**]** **:** *str***(**i**[**2**])** **for** i **in** preds**[**0**]}**
result **=** **{**k**:** v **for** k**,** v **in** *sorted***(**result**.**items**(),** key**=lambda** item**:** item**[**1**])}**
**return** result
3)制作一个简单的 Flask 应用程序来公开模型以进行推理
现在,我们在路线/
和/inference
上定义两个简单的端点。
/
(GET):第一个端点充当健康检查,以确保 API 启动并运行。/inference
(POST):第二个端点接受一个图像作为带有参数名image
的表单字段,并返回一个带有置信度得分和 ImageNet 类名的字典。
烧瓶应用程序定义
app
是稍后将由 Gunicorn 使用的 WSGI callable 的名称。要了解 WSGI 是什么,请查看下面有趣的链接部分。
app **=** Flask**(***__name__***)**
健康检查端点的定义
为了测试 API 是否启动并运行,我们只需在这个端点上点击一个 GET 请求来获得预期的输出。
@app**.**route**(**"/"**,** methods**=[**'GET'**])**
**def** **health_check():**
result **=** **{**
'outcome'**:**'endpoint working successfully'
**}**
**return** jsonify**(**result**)**
推理端点的定义
这里,我们接受一个POST
请求,从请求中发送的文件中提取image
参数。这以文件流格式存储,然后传递到PIL.Image.open
以准备图像。最后,我们执行一些简单的预处理,将PIL
图像转换为tf.Tensor
图像,并准备一批 1 个图像传递给我们的推理函数。然后,返回的结果被传递到jsonify
中进行响应准备和执行。
@app**.**route**(**"/inference"**,** methods**=[**'POST'**])**
**def** **perform_inference():**
image **=** request**.**files**[**'image'**]**
pil_img **=** Image**.**open**(**image**.**stream**)**
tensor **=** keras**.**preprocessing**.**image**.**img_to_array**(**pil_img**)**
tensor **=** tf**.**expand_dims**(**tensor**,** axis**=**0**)**
result **=** inference**(**tensor**)**
**return** jsonify**(**result**)**
4)定义一个使用 Gunicorn 进行部署的 Dockerfile
现在,我们已经完成了模型的定义,并使用一个简单的 Flask 应用程序为推断做好了准备。这里,我们开始编写一个Dockerfile
和一个.dockerignore
来构建一个定制的 Docker 映像。
FROM ubuntu**:**20.04RUN apt**-**get update **&&** apt**-**get install **-**y \
git \
curl \
ca**-**certificates \
python3 \
python3**-**pip \
sudo \
**&&** rm **-**rf **/**var**/**lib**/**apt**/**lists**/***RUN useradd **-**m docker_runnerRUN chown **-**R docker_runner**:**docker_runner **/**home**/**docker_runnerCOPY **--**chown**=**docker_runner ***.*** **/**home**/**docker_runner**/**flask_app**/**keras**-**docker**-**trial**/**USER docker_runnerWORKDIR **/**home**/**docker_runner**/**flask_app**/**keras**-**docker**-**trialENV PATH**=**"${PATH}:/home/docker_runner/.local/bin"RUN pip install **--**no**-**cache**-***dir* **-**r requirements**.**txtENTRYPOINT **[**"gunicorn"**,** "--bind"**,** "0.0.0.0:5000"**,** "--workers=4"**,** "app:app"**]**EXPOSE 5000
Dockerfile 文件
- 第一行从 Docker Hub 中提取
ubuntu:20.04
图像,准备一个容器,其中包含库存 Ubuntu 20.04 Focal Fossa。 - 第一个
RUN
命令下载并安装我们稍后需要的几个基本包。 - 下一个
RUN
命令添加一个名为 docker_runner 的用户,并为该用户创建一个主目录(使用-m 选项)。 - 下一个
RUN
命令更改目录所有权,并以递归方式为所有文件和子目录指定 docker_runner 作为其主目录的所有者(使用-R 选项)。 COPY
命令将 Dockerfile 所在的当前存储库中的所有文件移动到容器的目标目录中。USER
命令用于将当前活动用户更改为docker_runner
WORKDIR
命令用于将当前活动目录更改为/home/docker_runner/flask_app/keras-docker-trial
ENV
命令用于设置 PATH 环境变量,并将我们用户的/.local/bin
目录添加到其中。RUN
命令现在用于安装所有的需求,并且在安装时不使用任何缓存的目录或它们的 SHA 散列。ENTRYPOINT
命令用于使用gunicorn
开始 API 部署。我们绑定本地主机的端口 5000,并为此任务启动 4 个 workers。我们将 WSGI callable 指定为app:app
左侧的app
。如果你在步骤 3 中更改了 Flask 应用程序的名称,那么你应该将这部分更改为{your_app_name}:app
EXPOSE
命令用于让容器监听端口 5000。
。dockerignore
我们只是忽略了__pycache__/
目录,因为它从 CPython 生成中间文件。
__pycache__**/**
5)建立我们的形象
我们现在构建我们的图像,并给它分配一个标签keras-docker-trial
。
docker build **.** **-**t keras**-**docker**-**trial **--**file Dockerfile
6)定义一个简单的 GitHub Actions 工作流,以便在每次将图像推送到存储库时构建它
在这里,作为一个额外的步骤,我们使用 GitHub Actions 来构建我们的映像,作为每次对任何分支进行推送或者如果 PR 被合并到存储库中的测试。只有当您在 GitHub 上为您的模型准备一个存储库时,才需要添加这个。
name
:为工作流程指定一个名称。on
:定义何时使用工作流的触发器。env
:设置环境变量。jobs
:定义作为当前工作流的一部分运行的不同命令和工作流动作。runs-on
:定义哪个 GitHub 托管的 runner 用于执行工作流。actions/checkout@v3
:用于从仓库中签出代码。Build Docker Image
:从存储库中存在的 Dockerfile 文件构建映像。
name**:** Docker CIon**:**
push**:**
pull_request**:**
types**:** **[**'opened'**,** 'reopened'**]**env**:**
BUILD_CONFIGURATION**:** Releasejobs**:**
job1**:**
runs**-**on**:** ubuntu**-**latest
steps**:**
**-** name**:** Check**-**out the pushed code
uses**:** actions**/**checkout@v3 **-** name**:** Build Docker image
run**:** docker build **.** **-**t keras**-**docker**-**trial **--**file Dockerfile
测试管道
上面,我们已经定义了模型,并使用 Docker 和 Gunicorn 部署了它。您可以通过下面的 Postman API Explorer 找到一些部署及其预测的示例截图。
终端命令
获取健康检查请求
获取推理请求
通过邮递员请求发送的金鱼图像(根据 CC BY-SA 4.0 许可)
结论
上面,我们已经完成了一个简单的 Keras 模型的开发,它通过 Docker 的部署和一个用于 CI(持续集成)的 GitHub Actions 工作流。
未来范围
这只是作为一个简单的 MLOps 管道的一部分可以完成的工作的一小部分。CML(连续机器学习)和 DVC(数据版本控制)是两个重要的概念,是每个自我维持的机器学习工作流的一个组成部分,可以进一步探索。有趣的链接部分提供了相关资源。
参考
1.) Docker Hub 文档
2。) Keras 应用文档
3。) Gunicorn 文档
有趣的链接
1.)什么是 CML?
2。)什么是 DVC?
3。)什么是 WSGI (Web 服务器网关接口)?
4。)详细博客什么是 MLOps?
如何从 DEV 到 PRD 管理 Azure 数据工厂
原文:https://towardsdatascience.com/how-to-manage-azure-data-factory-from-dev-to-prd-ab7c8a2d10ae
使用 Azure DevOps 和 Azure Data Factory CI/CD 实用程序
管理从 DEV 到 PRD 的数据工厂管道—照片由 Ricardo Gomez Angel 在 Unsplash 上拍摄
1.介绍
在软件项目中,开发/TST/UAT 环境被用来开发和测试代码。之后,代码被发布到 PRD 环境中。Azure 数据工厂(ADF)项目遵循相同的分阶段方法。但是,需要注意以下 ADF 挑战:
- ADF 项目只能作为一个整体部署,而不是部署单个管道。在这种情况下,应该防止未经测试的代码最终进入生产环境。
- ADF 支持分支和拉请求,但是很难检查 JSON 中的变化。审查变更只能在 ADF 本身中完成,要么使用 DEV 中的不同分支,要么在 TST 中运行
- ADF 管道不能孤立测试,但是,通过固定数据源和 pytest 库,可以实现单元和集成测试。见我之前的博客。
在这篇 blogpost 和 git repo [azure-data-factory-cicd-feature-release](https://github.com/rebremer/azure-data-factory-cicd-feature-release)
中,讨论了如何优化 ADF 的发布周期,以防止未经测试的代码最终进入生产,另请参见下面的概述。
1.从 DEV 到 PRD 管理 ADF 按作者分类的图片
在此,主要观点如下:
- 多个开发人员使用 1 个 ADF 实例来创建功能。每个功能都有自己的分支。如果有太多的开发人员在同一个 ADF 实例上工作(> 10),可以决定为一组开发人员创建一个新的实例。
- 一旦一个特性准备好进行测试,它就会使用 ARM 模板部署到自己的 ADF 实例中。如果需要测试 N 个特性,这将导致 N 个 ADF 实例。这样,一个新的特性可以被孤立地测试,而不必先合并到主分支中。
- 一旦一个特性成功,它就被合并到主分支,随后,主分支被自动部署到 UAT 环境中。在 UAT 环境中,可以进行集成测试。也可以决定合并到一个专用的 UAT(预发布)分支,即在 UAT 测试成功后合并到 main。
- 一旦集成测试成功,主分支将部署到 PRD。请注意,部署到 PRD 总是发生在主分支,而不是特性分支。这是为了防止在 PRD 部署之后发生合并冲突,在最坏的情况下,这会导致撤销 PRD 中已经存在的特性。
在这篇博客的剩余部分,我们将讨论部署到不同环境的详细过程。最后,注意这篇博客遵循了 MSFT 推荐的新 ADF CI/CD 流程。在这个流程中,NPM Azure Data Factory utilities库而不是 ADF publish 按钮被用来传播到不同的环境。
2.偏差
在本博客的剩余部分,使用以下步骤部署项目:
- 2.1 先决条件
- 2.2 设置 Azure DevOps 项目
- 2.3 设置 ADF 开发实例
- 2.4 在 ADF 开发中创建特征分支
2.1 先决条件
本教程需要以下资源:
- 蔚蓝账户
- 天蓝色 DevOps
- Azure CLI (推荐,也用于故障排除)
随后,转到 Azure 门户并创建一个资源组,所有 Azure 资源都将部署在该资源组中。这也可以使用以下 Azure CLI 命令来完成:
az group create -n <<your resource group>> -l <<your location>>
2.2 创建 Azure DevOps 项目
Azure DevOps 是一个工具,可以持续地构建、测试和部署你的代码到任何平台和云。创建新项目后,单击存储库文件夹并选择导入以下存储库:
另见下图,其中使用本博客的 git repo 创建了一个 devops repo:
2.2.1 将存储库添加到您的 Azure DevOps 项目,image by author
随后,需要服务连接来访问资源组 fom Azure DevOps 中的资源。转到项目设置,服务连接,然后选择 Azure 资源管理器,另见下图。
2.2.2 将存储库添加到您的 Azure DevOps 项目,image by author
选择服务主体身份验证,并将范围限制到您之前创建的资源组,另请参见下图。
2.2.3 按作者将范围限制到资源组、图像
2.3 设置 ADF 开发实例
在这一段中,创建了用于开发的 Azure 数据工厂。此 ADF 开发实例应使用在步骤 2.2 中创建的 Azure DevOps git repo。
或者,Azure CLI 也可以用来创建数据工厂,包括添加代码库,见这里。请参见下面链接到 Azure DevOps git repo 的成功部署的 ADF 实例:
2.3 Azure 数据工厂实例链接到 Azure DevOps
2.4 在 ADF 开发中创建特征分支
一切就绪后,就可以开始开发了。软件开发的最佳实践是从主分支创建开发分支。在这个开发分支中,特性是由开发人员创建的。
在这篇博客中,关键是新的分支是在 Azure DevOps 中创建的,而不是 ADF 本身。这是因为 Azure DevOps Pipeline yml 文件也应该包含在新分支中(ADF 不会这样做)。转到您的 Azure DevOps 项目,选择分支并创建新分支,另请参见下文。
2.4 在 Azure DevOps 中创建新分支
开发人员现在也可以在 ADF 中找到分支,并可以在分支中开始编码。当一个开发人员完成他的代码后,他的分支将被其他开发人员审查和测试。这将在下一小节中讨论。
3.测验(test)
在这一章中,检查了一个特性分支,并将其部署到 ADF 实例中进行测试。执行以下步骤:
- 3.1 创建拉动式请求(PR)
- 3.2 将功能分支部署到新的 ADF TST 实例
3.1 创建拉动式请求(PR)
在开发人员完成其分支后,应创建一个 PR,以便其他人可以查看。转到 Azure DevOps 项目,转到分支,选择您的功能分支,然后选择新的拉请求,见下文
4.1 创建拉式请求
填写表格,并填写负责审查变更的开发人员的姓名。将向这些开发人员发送一封电子邮件通知他们。
3.2 将功能分支部署到新的 ADF TST 实例
正如介绍中所讨论的,很难从 JSON 中回顾 ADF 管道的变化。请购单应始终在 ADF 实例中审查。有三种不同的方法可以做到这一点,如下所示:
- 转到 ADF 开发实例,选择分支并查看更改。测试可能是一个挑战,因为分支机构仍然处于开发环境中
- 将更改部署到现有的通用 ADF TST 实例。将代码部署到现有管道将覆盖现有 ADF 实例。
- 将更改部署到具有功能分支名称的新的专用 ADF TST 实例。变更也可以单独测试。
本小节采用了新的专用 ADF TST 实例方法。转到你的 Azure DevOps 项目,转到你的 repo,找到[azure-pipelines-release.yml](https://github.com/rebremer/azure-data-factory-cicd-feature-release/blob/main/azure-pipelines-feature.yml)
并修改值以指向你的工作区,也见下文。
variables:
adfdev : "<<your dev ADF instance>>"
adftst : $(Build.SourceBranchName)
subiddev: "<<your dev subscription id>>"
subidtst: "<<your tst subscription id>>"
rgdev : "<<your dev resource group>>"
rgtst : "<<your tst resource group>>"
location : "<<your location>>"
AzureServiceConnectionId: "<<your AzureServiceConnectionId>>"
现在,在 DevOps 项目中选择管道,然后单击“新建管道”。转到向导,选择您之前创建的 Azure Repos Git 和 git repo。在“配置”选项卡中,选择“现有的 Azure Pipelines YAML 文件”,然后选择可以在 git repo 中找到的[azure-pipelines-release.yml](https://github.com/rebremer/azure-data-factory-cicd-feature-release/blob/main/azure-pipelines-feature.yml)
,也见下文。
一旦创建了管道,它就会立即运行,当运行成功时,一个新的数据工厂实例就会以特性分支的名称创建。在一个特征分支被正确地检查和测试之后,可以决定再次将它合并到主分支。这将在下一段讨论。
4.UAT 和珠三角
在本博客的剩余部分,使用以下步骤部署项目:
- 4.1 将特征分支合并到主分支
- 4.2 将主要分支部署到 UAT 民主同盟军
- 4.3 将主要分支部署到 ADF PRD
4.1 将特征分支合并到主分支
在特征分支被审查和测试正确后,它将再次与主分支合并。选择拉动请求,添加备注并将 PR 标记为完成,另请参见下图。
4.1 关闭 PR,将特征分支合并到主分支
特征分支现在合并到主分支。下一步,将在主要分支机构的 UAT 环境中运行回归测试。那将在下一段讨论。
4.2 将主要分支部署到 UAT 民主同盟军
主要分支始终是部署到珠三角。这样做是为了确保只有一个代码库在生产中使用。然而,在将一个特性合并到 main 之后,首先要运行几个回归测试,以确保 main 分支不包含冲突的变更。在这一段中,主要分支部署到了 UAT。
转到你的 Azure DevOps 项目,转到你的 repo,找到[azure-pipelines-release.txt](https://github.com/rebremer/azure-data-factory-cicd-feature-release/blob/main/azure-pipelines-main.txt)
,调整值指向你的工作区,也见下文
variables:
adfdev : "<<your dev ADF instance>>"
adfuat : "<<your uat ADF instance>>"
subiddev: "<<your dev subscription id>>"
subiduat: "<<your uat subscription id>>"
rgdev : "<<your dev resource group>>"
rguat : "<<your uat resource group>>"
location : "<<your location>>"
AzureServiceConnectionId: "<<your AzureServiceConnectionId>>"
现在采取第 3.2 节中描述的类似步骤来创建和运行管道。另外两点意见:
[azure-pipelines-release.yml](https://github.com/rebremer/azure-data-factory-cicd-feature-release/blob/main/azure-pipelines-feature.yml)
包含以下代码片段:trigger: main
。这意味着每当主分支中有变化时(例如,当一个特征分支被合并时),流水线就运行,并且测试可以被执行。- 创建 Azure DevOps 管道以部署到 UAT 只需一次
当测试成功执行后,代码就可以部署到 PRD 中了。这将在下一章讨论
4.3 将主要分支部署到 ADF PRD
当回归测试在 UAT 成功时,主分支机构准备在珠三角部署。这可以简单地通过在 4.2 中部署的管道中添加一个[deploy ADF to PRD](https://github.com/rebremer/azure-data-factory-cicd-feature-release/blob/main/azure-pipelines-feature.yml#L72)
任务来完成。关于回归测试和部署到 PRD 的两个附加备注:
- 自动测试 ADF 可能是一个挑战。在我之前的博客如何为 Azure 数据工厂构建单元测试中,广泛讨论了如何使用 DevOps 和 pytest 建立测试框架
- 为了防止版本自动部署到 PRD,可以在管道中添加一个手动验证步骤。这在我之前的博客中也讨论过,可以在附带的 azure 管道示例中找到
5.结论
在一个典型的软件项目中, DEV/TST/UAT 环境被用来开发和测试代码。之后,它被释放到珠江三角洲环境中。Azure 数据工厂(ADF)管道遵循相同的发布周期。然而,ADF 项目只能作为一个整体进行部署,并且存在未经测试的代码被部署到生产环境中的风险。在这个博客和 git repo [azure-data-factory-cicd-feature-release](https://github.com/rebremer/azure-data-factory-cicd-feature-release)
中,描述了如何管理 ADF 发布,另请参见下面的概述。
5.从 DEV 到 PRD 管理 ADF 按作者分类的图片
如何在苹果硅 M1 Mac 上管理 Conda 环境
使用 conda 管理 ARM64 和 x86 Python 环境
简·kopřiva 在 Unsplash 上的照片
本文描述了如何使用 conda 管理 ARM64 和 x86 Python 环境。要使用 pyenv(我的首选工具)和虚拟环境完成同样的事情,请参见我的文章 。
如果您使用 Python 的时间足够长,您最终将需要使用不同的 Python 版本来管理环境。当开始新项目时,你会想要利用最新的特性( Python 3.10 最近发布了!),但是您还需要维护使用以前版本的旧项目。作为一名数据科学家,我经常遇到这个问题——我经常回到旧的项目和代码,所以我需要一种简单的方法来管理使用不同 Python 版本的多个环境。
这就是康达的用武之地。Conda 是一个非常流行的包和环境管理工具(我们将讨论环境管理方面)。它允许您为不同的项目维护单独的环境——每个环境可以包含不同的包、不同的包版本,甚至不同的 Python 版本——并且可以快速轻松地在它们之间切换。
注意:本文面向 Mac 用户,尤其是 Apple Silicon Mac 用户,但基本的 conda 指令将在所有平台上工作。
使用 conda 创建 Python 环境
按照这些说明安装 conda 并开始使用环境。
1.安装康达
有几种口味的康达可用,其中一些描述如下。按照超链接查找安装说明。每个安装程序都将为您提供相同的环境管理工具。如果你不确定要安装哪个,就选 Miniforge。
- Miniforge(我的推荐) : 一个社区驱动的项目,支持多种系统架构。它创建了类似于 Miniconda 的最小 conda 环境(见下一个要点)。
- Miniconda:conda 官方最小安装程序。它创建了最小的 conda 环境,而没有自动安装任何软件包。
- Anaconda :原康达分布。它会自动将大量的 Python 包安装到新的 conda 环境中,因此它倾向于创建大型且臃肿的环境。我不推荐蟒蛇。
2.创造康达环境
创造康达环境非常容易。要使用特定版本的 Python(在本例中为 Python 3.9)创建一个新的 conda 环境,请从您的终端运行以下代码:
conda create -n myenv python=3.9
这将创建一个名为myenv
的新 conda 环境。要激活 conda 环境,运行conda activate myenv
(您可以通过conda env list
查看您所有 conda 环境的列表)。一旦环境被激活,你可以使用conda install
或pip install
安装 Python 包——conda install
更彻底地管理包版本的依赖关系,你必须使用pip install
来安装不能通过 conda 获得的包。
管理 conda 环境的完整文档链接此处。
苹果硅苹果电脑的其他挑战
上述步骤几乎总是足够了。然而,在较新的苹果电脑上(就我个人而言,我用的是 M1 MacBook Air ),你可能会在安装某些软件包时遇到问题。当苹果从英特尔芯片转到他们内部的苹果硅芯片时,他们从 x86 架构变成了 ARM64 架构。这在很大程度上是一件好事——你在日常使用中会注意到的唯一区别是,新芯片比旧芯片更快、更高效。
不幸的是,您可能偶尔会遇到包兼容性问题。苹果的 ARM64 架构尚不支持一些 Python 包——例如,我在使用 ortools 包时就遇到了这个问题。您将在安装期间得到错误,并且您将不能在您的代码中使用这个包。最终,当开发人员为他们的包添加 ARM64 支持时,这个问题应该会消失,但与此同时,您必须找到另一个解决方案。
**幸运的是,conda 提供了一个简单的短期解决方案:**您可以在 Apple Silicon Mac 上轻松创建 x86 架构的 conda 环境。很简单,不需要安装任何额外的软件。
使用 x86 架构创建 conda 环境
如果您需要使用只在 x86 架构上工作的包,只需遵循这些步骤。首先尝试前面的步骤,只有在遇到软件包安装问题时才到这里来。否则,您会牺牲性能而没有任何好处。
1.安装 conda(如果您还没有安装的话)
遵循与上一节中步骤 1 相同的说明。您不需要安装一个单独版本的 conda 来处理 x86 环境。
2.创造康达环境
这是指令有点不同的地方,但只是一点点不同。我们只需要告诉 conda,我们希望我们的环境使用 x86 架构,而不是原生的 ARM64 架构。我们可以通过下面几行代码来实现,这些代码创建并激活一个名为myenv_x86
的新 conda 环境:
CONDA_SUBDIR=osx-64 conda create -n myenv_x86 python=3.9
conda activate myenv_x86
conda config --env --set subdir osx-64
第一行创建环境。我们简单地设置CONDA_SUBDIR
环境变量来指示 conda 应该使用 x86 Python 可执行文件创建 en environment。第二行激活环境,第三行确保 conda 将 x86 版本的 Python 包安装到环境中。
我在我的~/.zshrc
文件中创建了一个简单的 shell 函数,这样我就不需要在每次创建新的 x86 环境时记住确切的命令。
### add this to ~/.zshrc (or ~/.bashrc if you're using Bash)create_x86_conda_environment () {
# create a conda environment using x86 architecture
# first argument is environment name, all subsequent arguments will be passed to `conda create`
# example usage: create_x86_conda_environment myenv_x86 python=3.9
CONDA_SUBDIR=osx-64 conda create -n $@
conda activate $1
conda config --env --set subdir osx-64
}
就是这样!一旦您创建了 x86 环境,它的工作方式与使用默认系统架构的常规 conda 环境完全相同。只需开始安装软件包,您就可以开始了!
结论
如果你是 Apple Silicon Mac 用户,你可能偶尔会遇到软件包安装问题。最终,在开发人员有足够的时间将 ARM64 支持添加到他们的包中后,这些问题应该会消失,但对于一些利基包来说,这可能需要几年的时间。同时,本文演示了如何使用 conda 创建与不支持 ARM64 的包兼容的环境。希望这篇文章能帮你省去一些故障排除!
Python 版本管理可能很棘手,但 conda 提供了一个很好的解决方案。我喜欢的另一个工具是 pyenv(与虚拟环境相结合)——详情见我的文章这里。如果你有另一个你更喜欢的工具,我很乐意听听它!
成为媒体会员访问成千上万作家的故事!
如何有效管理数据项目和团队
原文:https://towardsdatascience.com/how-to-manage-data-projects-and-teams-effectively-baf02025a367
重新评估我们的工作方式从来都不是一个坏主意。无论你是一名从事投资组合项目的学生,一名管理端到端管道的经验丰富的 ML 工程师,还是一名负责整个数据团队成功的高管,都是如此。
这可能是你最终拒绝的多余的一步。也许你决定修改每周团队电话会议的形式,或者进行最后一次质量检查,这需要几分钟,但偶尔可以节省几个小时。您的里程可能(并且很可能)会因团队和学科而异,但想法是相同的:您的工作流几乎肯定可以从一些调整和简化中受益。
为了帮助你用一些具体的想法开始这个旅程,我们选择了最近在数据科学、领导力和项目管理的交叉点上的几个杰出人物。尽情享受吧!
- 如何解决你的数据科学项目 。离群值、缺失值、不平衡的数据集:迟早,你会在最糟糕的时候遇到这些。杰森·庄用一本关于你作为一名数据科学家可能遇到的一些最常见问题的入门书挽救了局面,并提出了“一个关于如何正确处理[它们]以及它们各自的权衡的框架”
- 新领导角色的挑战与回报 。 CJ Sullivan 回顾了一个重大的职业转变:从技术行业到滑雪行业,从一名个人贡献者到成为数据科学总监。她的文章揭示了这种变化可以教会我们如何领导他人,以及如何调整我们向非技术利益相关者传达工作价值的方式。
- 路线图里有什么? 弄清楚如何实现我们为自己设定的目标可能需要一个漫长的试错过程,但首先要实现正确的目标更为棘手。 Marie Lefevre 阐述了定义良好的路线图对数据团队的好处,并分享了一个创建路线图的框架,该框架将为您提供“战略性思考而非操作性思考”的空间
Artem Kostelnyuk 在 Unsplash 上拍摄的照片
- 构建健壮数据平台的重要性 。缩小数据对企业的潜在价值和实际影响之间的差距通常可以归结为将正确的工具放在正确的人手中。Mahdi Karabiben 探讨了数据目录目前对利益相关者的(许多)限制,并主张减少 ui,增加 API,推动更大的数据可访问性。
- 要做出正确的决策,你需要找到正确的指标 。"你如何严谨、科学地研究那些你无法轻易定义的概念?"在你收集和分析数据之前,Cassie Kozyrkov 让我们注意到一项艰巨的任务,那就是对我们要测量的现象提出一个清晰、可行的想法。
- 为什么数据项目通过迭代和共情蓬勃发展 。数据科学家是问题解决者;正如泰勒·詹森解释的那样,更好地理解他们内部客户的目标至少与对算法和统计的深刻理解同等重要(如果不是更重要的话)。Taylor 建议借用设计思维的原则——从移情到原型——对数据团队来说是一个强有力的举措。
当你让这些关于团队和项目管理的想法渗透进来的时候,我们希望你也可以花一些时间阅读一些我们最近发表的优秀文章。
- 我们欢迎 Anna Rogers 的第一份 TDS 贡献——在生成式人工智能工具的背景下,对原创性和归因的发人深省的反思。
- 人工智能生成的艺术也是 Danie Theron 研究稳定扩散图像的视觉输出中的性别、肤色和交叉偏见的首选。
- 关于正则表达式以及如何在 Python 中使用它们的全面的一站式资源,请不要错过 Susan Maina 的最新文章。
- 如果你的数据科学职业还处于早期阶段, Arunn Thevapalan 的第一篇 TDS 帖子为你进入提供了一张有用的路线图。
- Furcy Pin 关于 Hadoop 生态系统的详细历史是一个有用的提醒,告诉我们大数据实际上是多么新(相对而言)。
- 最近科技领域的裁员潮对人工智能的未来意味着什么? Wouter van Heeswijk 博士怀疑人工智能冬天是否即将来临。
感谢您支持我们发表的作品。如果你想产生最大的影响,考虑成为的中层成员。
直到下一个变量,
TDS 编辑
如何在不使用熊猫的情况下在 Python 中操作和分析数据
使用基本的内置 Python 函数分析未来人口增长
如果你正在使用 Python 并且想要做数据分析,你可能会使用 Pandas 库。这是有原因的,因为 Pandas 是一个快速灵活的数据处理和分析工具。然而,对于刚接触 python 的人来说,我发现回到 Python 的基本构建块进行数据分析是有用的,可以帮助我更好地学习 Python 进行基本的数据讨论。所以作为一个 Python 练习,我将在不使用 Pandas 库的情况下用 Python 做数据分析。我们将根据联合国提供的数据分析未来的人口增长。
我们将分析表格数据,这意味着我们将处理存储在二维列表中的数据。为了操作 2D 列表,我们将大量使用简单的嵌套 for 循环、索引和内置 python 函数,如 min()、max()、sort()和 append()。您将在使用 Pandas 或其他库的工作流程中使用的工具。
数据*是从 Gapminder 下载的。完整的数据集包含了 197 个国家从 1800 年到 2100 年的年度预测。我使用了从 2020 年到 2100 年所有 197 个国家的数据子集,时间间隔为 5 年。
数据集和代码可以在这个 Github repo 中找到。
导入数据
正如您在结果中看到的,数据存储在一个二维列表中,其中每一行都是列表中的一个元素。该表采用宽格式,其中每一“行”是一个国家,每一年是一“列”。这意味着列表中的每个列表都包含每个国家的所有人口信息。
创建汇总表
我们将通过创建一个汇总表来开始分析人口数据集,该表包含每个国家的最高和最低预期人口信息,以及从现在到 2100 年的相对人口变化。我们将创建一个名为pop_exp_dev
的表,其中包含以下各列:
- 国家
- 最低预测人口
- 最低预测人口年份
- 最高预测人口
- 最高预测人口年份
- 2020 年至 2100 年人口的相对变化
我们通过几个步骤创建这个表。
- 首先,我们需要将人口数据转换为整数值。我们通过使用嵌套的 for 循环来实现这一点。外部循环遍历每一行,内部循环遍历行中的每一项,并将每一项从字符串转换为整数。我们从索引 1 开始外部循环,因为我们不需要转换包含列名的第一行。我们还从索引 1 开始内部循环,因为每行的第一个值包含国家名称。
- 我们创建一个空列表
pop_exp_dev
,在其中存储新的值。 - 为了找到新值,我们使用 for-loops 来遍历行,以找到最高和最低值,并将它们追加到新表中。我们还找到了它们的索引值,这样我们就可以识别和附加这些值的年份。
- 最后,我们希望找到 2020-2100 年期间以百分比表示的预期人口变化。我们用公式pop _ 2100-pop _ 2020/pop _ 2020 * 100来计算
作者图片
我们现在有一个表格,其中有一些人口数据的摘要。在 2D 列表中查看数据看起来不是很舒服,所以为了便于说明,我展示了如果您以表格形式查看我们创建的表时的样子。
作者图片
可视化子集列表
从这张表中,我们可以画出几幅图来显示预期的人口数量。把 197 个国家都标在一个情节里很快会让情节太长,很难读懂。相反,我们可以将表格的一部分分成子集,绘制更小的图。在这里,我们将把人口增长最快和人口下降最快的国家划分为一个图,将所有欧洲国家划分为另一个图。
最大人口增长和最大人口下降子集
对于第一个图,我们简单地按照相对变化的值对 2D 列表进行排序,该值存储在列 6(索引 5)中。我们使用 sorted()来做到这一点,并将一个 lambda 函数传递给 key 参数。
作者图片
该图显示,我们可以预期看到非洲国家人口增长最多,欧洲国家人口下降最多,但牙买加除外,它将是所有国家中人口下降最多的国家。
作者图片
欧洲的子集国家
为了创建欧洲国家的子集,我们手动创建一个包含欧洲所有国家的列表,并循环遍历pop_exp_dev
列表,以查找与 Europ 列表中的国家相匹配的任何元素。
作者图片
创建一个水平柱状图,我们可以看到大多数欧洲国家预计到 2100 年人口会下降。
作者图片
将表格标准化,以比较国家之间的人口发展
由于一些国家人口多,一些国家人口少,很难比较它们的人口发展情况。我们可以通过归一化人口值来解决这个问题。为此,我们将 2020 年设定为一个指数年,所有其他年份都将与该指数年相关联。每一年的人口数除以指数年的人口数,再乘以 100。
作者图片
正如您在结果中看到的,2020 年被设置为索引年,值为 100。其他年份的人口以相对于 2020 年人口的百分比变化表示。
人口数据标准化后,我们可以通过对列表进行子集化来选择要绘制的国家,如前所示。这里,我们绘制了澳大利亚、日本、摩尔多瓦、瑞典、英国和美国的人口发展图。在这些国家中,澳大利亚预计将出现最大的人口增长,其次是美国、瑞典和英国。日本和摩尔多瓦的人口预计都将下降。
作者图片
结论
对于处理杂乱的数据或进行更高级的分析,我无疑会使用熊猫。事实上,我不建议任何人在实际工作流程中采用这种变通方法,因为这远不是分析数据的最佳方式。例如,为了编写高效的代码,最好是避免 For 循环并对操作进行矢量化。尽管如此,我发现对人口数据进行这种简单的分析有助于我更好地掌握 python 的基本功能,比如如何通过使用简单的或嵌套的 for 循环来访问二维列表中的某些项目和元素。以及如何使用 for-loops 创建项目并将其追加到新的二维列表。我希望这些例子对你有用!
*本文使用的数据基于联合国通过【GAPMINDER.ORG、CC-BY LICENSE 提供的免费资料
</5-common-misinterpretations-of-the-p-value-aacaa6dcfddd>
如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。每月 5 美元,你可以无限制地阅读媒体上的故事。如果你注册使用我的链接,我会赚一小笔佣金。
https://medium.com/@andreagustafsen/membership
如何最大化数据分析的价值
原文:https://towardsdatascience.com/how-to-maximize-the-value-of-your-data-analysis-309059dcd243
在最近一篇关于数据集市、的好处的文章中,Vicky Yu 强调了一个令人惊讶的统计数据:就在几年前,数据科学家将花费高达 80%的工作时间来争论和清理数据。即使这一比例现在有所下降(正如一些调查所显示的),但留给分析和洞察的时间仍然相对较少。这让人不禁想问:难道不应该是数据专业人员工作的核心吗?
本周,我们转向数据分析的关键领域(尽管有时讨论不足),并分享最近的几篇文章,这些文章关注分析师应该如何工作,以及他们如何充分利用有限的时间和强大的技能。
- 学习如何找到给定问题的最佳解决方案 。可靠的分析会产生好的决策。正如 Julia Kho 所解释的,这正是优化所做的:她的新文章向我们展示了不同层次的分析和基于数据解决问题的各个组成部分。
- 组织可以帮助团队成员更有效地利用时间 。对于Mikkel dengse来说,研究为什么数据分析师最终会花费大量时间在乏味、重复的任务上,而不是分析数据,这一点很重要。只有这样,团队才能重组和重新关注他们最有价值的工作流程。
爱丽丝·迪特里希在 Unsplash 上拍摄的照片
- 难道我们做探索性数据分析全错了?“EDA 不是一个人可以执行的特定指令集——它是一种对数据进行思考的方式,也是一种练习好奇心的方式。”Viyaleta Apgar 最近的帖子发人深省,邀请我们重新评估我们进行分析的方式,避免在没有反思我们自己的假设、偏见和盲点的情况下仓促行事。
- 一瞥医疗保健数据分析师的日常经历 。以数据为中心的工作在不同的行业和工作场所看起来会有显著的不同,这就是为什么了解从业者的真实生活经历是如此有用。 Rashi Desai 慷慨地分享了她对医疗行业数据分析工作的第一手印象,并消除了一些常见的误解。
想在本周探索更多的话题吗?我们当然希望如此!以下是一些我们认为你会喜欢的近期杰出作品:
- 在我们最新的作者聚焦中,我们有幸与 Tessa Xie 就数据科学职业道路的曲折和公开写作的好处进行了交谈。
- 您应该如何比较具有全部或部分共同变量的回归模型?Sachin Date 最近的深度潜水详细探讨了这个问题。
- Suneeta Mall 发表了她自己对一个同样有趣的问题的深度探讨:标注错误的问题以及它们如何影响深度学习项目的结果。
- 你在找新工作吗(或者打算马上开始工作)?不要错过艾玛·丁关于你绝对应该避免的三个求职错误的便捷资源。
- 对于任何想尝试一个很酷的新事物的有创造力的修补者来说,这里是 Chanin Nantasenamat 关于用 Python 构建一个实时转录应用的教程。
- 对于更倾向于理论的人来说,这里有一个对卷积神经网络中的多维傅立叶变换的彻底而迷人的探索,由 Sascha Kirch 提供。
- 最后,我们以六月版开始了新的一个月,它收集了我们关于 SHAP 图书馆和可解释的人工智能的一些最好的文章。
您的支持对我们非常重要,无论是阅读和参与我们作者的作品,与您的朋友和同事分享,还是成为媒体成员。谢谢大家!
直到下一个变量,
TDS 编辑
如何度量异常值概率
原文:https://towardsdatascience.com/how-to-measure-outlier-probability-b7a990e819cc
一种计算点为异常值的概率的方法
离群值对于数据科学家来说是个大问题。它们是数据集中的“奇怪点”,必须对其进行检查,以验证它们是错误还是真实现象。有几种算法可以帮助我们检测异常值,但我们有时需要测量某个点是异常值的概率,而不是 0-1 值。让我们看看一个可能的方法。
什么是离群值?
异常值实际上有几种定义。一般来说,它是一个离它所属的数据集的分布中心太远的点。这些点实际上是“奇怪的”,如果我们想用那个数据集填充我们的模型,就必须提前检查。机器学习模型可能不总是能够直接处理异常值,它们的存在可能会显著影响训练。
这就是为什么我们首先需要将一个点标记为离群点,然后检查它是否必须被删除。
如何检测异常值
有几种算法可以帮助我们检测异常值。四分位数范围是单变量数据集最常用的方法(例如,在箱线图的计算中使用)。多元数据集可能受益于高斯包络线或隔离森林。这些算法中的每一个都对数据集的每个点应用一个标签,如果该点不是异常值,则该标签为 0,否则为 1。
但是如果我们需要知道一个点是异常值的概率会发生什么呢?我们可以使用一个有用的工具来达到这个目的。
自举
关注我的出版物的人都知道我喜欢 bootstrap。这是数据科学家可以使用的最有用的统计工具之一。它允许我们计算测量的精度,并且异常值的检测实际上是一种测量。因此,让我们看看 bootstrap 的一种可能用途,根据给定的数据集计算某个点是异常值的概率。
这个想法是对我们的数据集进行重采样,对于每个生成的样本,检查每个点是否是异常值。您选择的算法无关紧要,所以您可以随意使用您喜欢的任何过程。然后使用从数据集生成的新样本再次重复该过程。由于数据集已经改变,一些原始点可能不再是异常值,而其他点可能由于同样的原因已经变成异常值。
根据需要多次重复该过程,并为每个原始点计算被标记为异常值的样本分数。这是你的概率。
那么,正式的程序是:
- 对于数据集的每个点,如果该点不是异常值,则计算等于 0 的标签,否则计算等于 1 的标签
- 使用替换对整个数据集进行重新采样,并创建一个相同大小的新数据集
- 重复步骤 1 和 2 数百次
- 计算生成的样本中标签的平均值
Python 中的一个例子
现在,让我们看看如何使用 Python 编程语言来计算异常值的概率。对于这个例子,我将使用我在本文的中谈到的 IQR 方法。
首先,我们导入 NumPy。
import numpy as np
然后,让我们用一个正态分布生成的 30 个伪随机数来模拟一个数据集。
np.random.seed(0)
x = np.random.normal(size=30)
众所周知,正态分布中出现大数(即大于 3)的概率很低。让我们添加一个人为的异常值,例如 5。
x = np.append(x,5)
正态随机变量具有大于 5 的值的概率是 0.000000287,因此我们可以说,这样的点,如果出现在从正态分布生成的数据集中,一定会引起一些怀疑。那么这是一个异常值。
现在让我们写一个函数,对于一个给定的点和数组,如果该点是一个离群点,则给我们 1,否则给我们 0。
def check_outlier(value, array):
q1 = np.quantile(array,0.25)
q3 = np.quantile(array,0.75)
iqr = q3-q1
return int(value > q3+1.5*iqr or value < q1-1.5*iqr)
让我们将此函数作为地图应用于原始数据集,并检查结果。
result = np.array(list(map(lambda t: check_outlier(t,x),x))).reshape(1,-1)
正如我们所看到的,所有的点都是“好”的,最后一点被正确地标记为异常值。
现在让我们应用 bootstrap 来计算概率。让我们记住这些步骤:对数据集重新采样,计算每个点现在是否是异常值,重复数百次(本例中为 500 次),然后计算我们的点被标记为异常值的数据集的比例。
n = 500
result = None
for i in range(n):
new_x = np.random.choice(x,replace=True, size=len(x))
outliers = np.array(list(map(
lambda t: check_outlier(t,new_x),x))).reshape(1,-1) if result is None:
result = outliers
else:
result = np.concatenate((result,outliers))
概率可以计算为 0-1 标签的平均值。
scores = np.apply_along_axis(np.mean,0,result)
现在让我们看看每个点及其分数:
np.concatenate((x.reshape(-1,1),scores.reshape(-1,1)),1)
正如我们所见,-2.55298982 被认为是一个异常值,有 69.6%的概率。这很现实,因为这个数字对于正态分布来说很“奇怪”,尽管它不像 5 那样“太奇怪”,5 被认为是 98.6%概率的异常值。所以,我们可以说这些分数其实是有意义的。
总的想法是按照分数降序排列我们的值。得分最高的记录很可能是异常值。
结论
在本文中,我提出了一种算法,对数据集的每条记录应用一个分数,该分数表示它是异常值的概率。这个过程的主要成分是自举技术。该算法适用于您使用的任何异常值识别技术,甚至可用于多元数据集。由于离群值的定义相当主观,我认为计算分数而不是 0-1 标签可能有助于数据科学家从我们的数据中提取更多信息。
原载于 2022 年 3 月 15 日【https://www.yourdatateacher.com】。
如何衡量你的数据团队的投资回报率?
原文:https://towardsdatascience.com/how-to-measure-the-roi-of-your-data-team-9c60a939f247
并证明在数据人员、数据工具等方面的支出是合理的…适当地
衡量数据团队的投资回报率—图片来自 Castor
I .为什么衡量您的数据团队的投资回报率如此重要?
衡量数据团队投资回报率的重要性—来自 Castor 的图片
我感到困惑的是,尽管数据团队花了很多时间来量化一切,但他们仍然很难量化自己的表现。
问题是,如果不能证明数据团队对业务有重大的、可衡量的影响,他们就不能放弃。原因很简单。数据团队需要相应的投资来高效运作。我们知道投资通常需要充分的理由。出于这个简单的原因,如果你能证明你的数据团队的经济影响,你将永远只能协商预算,投资工具或壮大你的数据团队。你可能已经知道了。问题是:如何衡量这种影响?
这件事已经有人考虑过了。事实上, Benn Stancil 、Mikkel dengse和 Barry McCardel 已经提出了三个有见地的框架来衡量数据团队的 ROI。
通过与 Clearbit 的数据主管 Julie Beynon 和 Khan Acadamy 的数据主管 Kelli Hill 的讨论,我们试图了解这些框架在实践中是如何应用的。这有助于我们确定可行的步骤,使您能够以简单而有意义的方式衡量数据团队的投资回报率,同时考虑到您团队的规模和成熟度。
二。为什么衡量数据团队的投资回报率如此困难?
- 数据团队相对较新,或者至少比财务、营销和工程团队新。因此,还没有确定的衡量数据 ROI 的最佳实践。尽管已经出现了各种框架来衡量数据团队的 ROI,但是还没有普遍的方法来这样做。
- 数据团队以一种非常独特的方式运作。他们通常支持其他团队,如营销、财务或工程团队,以影响绩效。因此,他们会间接影响业务,这就是为什么还不能 100%确定应该跟踪哪些 KPI 来评估他们的绩效。
- 最后,数据团队需要考虑的相关 KPI 集根据特定行业、团队的规模和成熟度而有所不同。这也使得很难建立一种通用的衡量绩效的方式。
三。衡量您的数据团队的投资回报——来自数据领导者的重要提示。
A.数据团队的两个关键阶段及其各自的 KPI
I)阶段 1:清理数据
“干净的数据是我的第一个投资回报”,引自 Julie Beynon
新数据团队的首要任务是获得干净、可用和可信的数据。如果没有这一点,数据就无法影响企业的整体绩效。在数据团队的早期阶段,你需要确保数据是好的,你的工作是润色你的数据,直到它处于最佳状态。自然地,您将测量的第一个 KPIs 指标与数据质量相关联。数据质量是一个总括术语,涵盖了影响数据是否可用于预期用途的所有因素。因此,您测量的第一个数据 ROI 与您能否从干净的数据中获得答案紧密相关。以下是确保您的数据至少 80%良好的最重要的衡量要素。关于数据质量维度的更多内容,【Metaplane 的这篇文章是一个很好的资源。
数据质量测量及其相关指标—来自 Castor 的图片
- 精度
准确性与你拥有的数据是否描述现实有关。例如,如果您这个月在数据仓库中销售的商品数量与销售团队报告的实际数量不一致,那么您就遇到了准确性问题。
衡量准确性的关键指标:“当与参考集比较时,您的数据集匹配的程度,与其他数据一致的程度,通过规则的程度,以及对数据错误进行分类的阈值的程度。”(凯文胡,2021 )
2.完整性
完整性与你的数据描述现实的完整程度有关。完整性的两个层次如下:首先,您需要查看您的数据模型有多完整。其次,你应该看看数据本身相对于数据模型有多完整。
衡量完整性的关键指标:“针对映射的验证程度、空数据值的数量、缺失数据、满足的约束的数量。”(凯文胡,2021 )
3.一致性
一致性是指你的数据内部是否一致。当不同值的聚合与应该聚合的数字不一致时,数据就是不一致的。例如,如果每月的利润与每月的收入和成本数字不一致,那么就存在一致性问题。一致性检查的一个例子是 Codd 的引用完整性约束。
衡量一致性的关键指标:“通过检查的次数,以跟踪值或实体的唯一性,以及参照完整性是否得到维护。”(凯文·胡,2021 )
4.可靠性
可靠性与数据用户是否认为您仓库中的数据是真实的有关。当你有足够的血统和质量保证时,你的数据可以被认为是可靠的。如果您的销售团队认为由于技术问题,产品的使用不能反映真实的使用情况,那么您就面临着数据可靠性的问题。一个数据目录通常可以帮助你快速获得数据可靠性的证明。
衡量可靠性的关键指标:“验证最终用户系统中数据的请求数量、认证数据产品的数量、最终用户可用谱系的全面性、使用系统的用户数量。”(凯文胡,2021 )
5.可用性
这指的是数据能否被顺利访问和理解。当数据易于理解并以明确的方式正确解释时,数据可用性就很好。当一个外观仪表板很难理解时,你就有一个可用性问题。总的来说,用元数据丰富你的数据(即记录你的数据)使它在移动中变得可用和容易解释。
衡量可用性的关键指标:“以不同方式呈现数据的请求数量,数据集的文档化水平,使用系统的用户数量。”(凯文胡,2021 )
第二阶段:运作化
一旦您掌握了干净、可靠的数据,提高性能的下一步就是进行运营分析。这种方法包括让“运营”团队可以访问数据,用于运营用例(销售、营销,…).我们将它与将存储在仓库中的数据仅用于报告和商业智能的更经典的方法区分开来。运营分析不是使用数据来影响长期战略,而是为业务的日常运营提供战略信息。简而言之,就是让公司的数据发挥作用,让组织中的每个人都能做出更明智、更快速的决策。
运营分析—将数据从您的仓库推送到运营工具。图片来自 Castor
这是数据团队发展过程中非常自然的一步。收集数据的最终目的是提高组织的效率和决策。接下来,您应该衡量如何将数据交给其他团队,以便他们能够以独立的方式使用数据。这意味着将数据推入运营工具,以便销售或营销团队可以在他们的活动中有效地使用这些数据。逆向 ETL 工具非常适合数据操作化,允许你自动将数据从你的仓库推到其他团队的操作工具中。
数据操作化有两个好处,可以让您提高投资回报率。首先,它允许其他团队做出更有效的、数据驱动的决策。其次,这解放了分析团队,让他们能够进行更深入、更有意义的数据分析。当分析可以脱离基本的报告、向其他团队提供数据事实和回答问题时,他们可以专注于我们真正需要分析师技能的事情。
但是,您如何衡量自己在自助服务中推出数据的能力呢?
Clearbit 的数据主管 Julie Beynon 建议从你为其他团队解决问题的数量来考虑这个问题。您可以专门查看特定类别中请求数量的减少情况。例如,数据团队可能会收到很多关于归属的请求。将相关数据放在营销团队手中,应该会导致后者在这类问题上对数据团队的依赖减少,最终将归因相关请求的数量降至零。衡量数据可操作性的一个好方法是查看不同类别中请求数量的减少。你能从列表中剔除的问题越多,你的数据就越容易操作。
这个想法也出现在 HEX 提出的一个著名的数据 ROI 框架中。该框架认为,如果您的数据团队真正提供了价值,其他职能部门(如营销或财务)的领导会强烈主张代表您对团队进行更多投资。相反,如果你的合作伙伴不愿意为你辩护,你可能没有将你的数据操作化。也就是说,其他团队没有从你的工作中受益,或者你不允许他们独立处理数据。
B.不同的子团队有不同的 ROI。
我们已经确定,您应该根据数据团队所处的阶段查看不同的指标。但不是这样。数据团队由子团队组成,这些子团队应该根据不同的 KPI 指标进行评估。我们区分以下两个主要的子团队:工程和分析。这些子团队中的每一个都有不同的目标,并以不同的方式影响业务,因此为什么他们应该被不同地评估。
在一篇关于衡量数据工作投资回报率的非常酷的文章中,Mikkel dengse介绍了系统人员和 KPI 人员之间的区别。我们把这种区别变得更简单,我们只从工程(系统人员)和分析(KPI 人员)的角度来谈。
系统人员与 KPI 人员—图片来自 Mikkel Dengsoe
I)工程(系统)
数据工程团队的目标是构建可靠的基础架构,以确保分析人员能够访问可信数据。因此,以下指标最适合用于衡量他们的绩效
乘数效应
工程师的工作不会直接影响顶级 KPI。他们工作的独特之处在于,它起到了“乘数效应”的作用,让分析团队工作得更快、更有效率。例如,如果数据工程师可以让 dbt 移动得更快,分析工程师也可以移动得更快,并建立更多的数据模型。如果没有工程团队,数据分析师和数据科学家将花费 70%-80%的时间清理数据。拥有一个强大的工程团队可以提高分析团队的绩效,这反过来会积极影响其他团队的绩效。
但是如何衡量乘数效应呢?嗯,数据工程功能通过向其他团队提供干净、可靠的数据,允许其他人更快地行动。因此,衡量数据工程师绩效的关键指标是数据质量和数据正常运行时间。
数据质量
我们已经在第一部分中详细介绍了数据质量包含的组件。在更一般的情况下,数据质量可以通过数据问题触发的事件数量来衡量。我们可以将数据事件定义为包括内部警报、失败的测试以及外部消费者提出的相关问题。
数据正常运行时间
数据正常运行时间可以定义为数据集按时交付的时间相对于预期频率或 SLA 要求的百分比。
预期频率指的是数据集的预期更新频率。这通常是每天、每小时或实时的。
SLA(服务水平协议)要求是由数据生产者和消费者之间的 SLA 协议规定的频率条款,规定数据必须在何时更新。例如,SLA 可能会规定一个绝对时间,如早上 7:00,或者一个相对时间,如每 3 小时一次。
基础设施成本节约
我们最初惊讶地听到,在 KhanAcademy 的数据团队中,在衡量分析工程团队的绩效时,通常会考虑基础架构成本节约。让我们思考一下,为什么这种测量会有启发性。
除了向其他团队提供干净可靠的数据,数据工程师还负责良好的数据管理。这包括清理表格、归档不必要的表格,以及充分利用云所提供的优势。事实证明,良好的数据管理可以在存储成本方面节省大量资金。类似地,数据工程师通常寻求自动化流程或使其更高效。这节省了时间和金钱。因此,基础设施成本的节约是表现良好的数据工程团队的自然结果。从这个意义上说,在衡量你的团队的表现时,这是一个非常有趣的指标。当然,你需要保持谨慎,并且总是在引擎盖下寻找成本下降的原因。你的团队是更有效率了(好现象)还是他们只是处理的数据比以前少了(不好了)?不管答案是什么,这个数字除了非常容易测量之外,还会告诉你一些事情。
II)分析(关键绩效指标)
分析团队以不同的方式工作。他们对业务 KPI 有更直接的影响,或者至少他们更接近决策。评估他们的表现应该考虑到这一点。
在分析方面,真正重要的是从提出问题到给出答案之间的周转时间。分析的工作是为关键问题提供快速答案,从而启发企业的决策。目标是最小化从提出问题到分析师给出答案之间的时间,并且测量这个时间应该给出团队表现的一个很好的指示。这个框架最初是由 Benn Stancil 提出的,并被证明在 KhanAcamedy 的数据团队中运行良好。
以这种方式衡量分析性能的好处在于,它鼓励分析师将工作重点放在现实生活的决策上,避免他们迷失在探索性的数据分析中。
你的分析团队关注什么?这说明了您业务中的大量数据投资回报率。很简单,如果你的团队花了大部分时间为其他团队(营销、财务等)答题,这意味着你的数据没有被操作化。其他团队完全依赖分析团队解决数据问题,而您无法实现数据自助服务。这也意味着你的分析团队花了太多时间运行,解决日常业务问题和基本报告,而不是构建并专注于更深层次的分析。尽管这一指标无法充分衡量,但它让您很好地了解了自己在数据之旅中的位置。这也有助于您确定应该关注哪些指标。如果您的数据没有完全可操作化,您可能应该在**数据质量上花费更多时间,**确保您拥有干净的&可信数据。
结论
这些思考带给我们一个甜蜜的结论和一个相对简单的解决数据 ROI 难题的方法。一旦您理解了您的数据团队当前面临的挑战(数据质量或数据可操作性),确定您应该关注的用于测量性能的指标就非常简单了。我们试图通过这个很酷的地图让事情变得更简单。下面是怎么读的。您的数据团队相对年轻,您还没有解决数据质量问题?这意味着你处于第一阶段。您应该关注数据准确性、一致性和正常运行时间等指标来评估工程职能的绩效,同时您应该关注文档工作和数据可用性来衡量数据分析师的绩效。就这么简单。
衡量数据团队投资回报率的指南针—来自 Castor 的图片。
关于我们
我们写了利用数据资产时涉及的所有过程:从现代数据堆栈到数据团队组成,再到数据治理。我们的博客涵盖了从数据中创造有形价值的技术和非技术层面。
想去看看卡斯特吗?联系我们,我们将向您展示一个演示。
如何用 Python 将大型 CSV 文件合并成单个文件
深入 Python,学习如何使用几行代码自动完成合并大块 CSV 或 Excel 文件等任务。
照片由 Pexels 的 Adriano Brodbeck 拍摄
建议的点播课程:
你们中的许多人联系我,询问用 Python 自动化 Excel(以及一般的电子表格)任务的宝贵资源。 下面我分享四门我会推荐的课程:
- 中级 Python(纳米级) 或 数据分析师| Python + SQL(纳米级) 非常高质量的课程,适合致力于学习更高级 Python 的人! → 通过此环节获得七折优惠
- Excel 用户 Python 编程(Numpy &熊猫)
- Python 面向电子表格用户(熊猫&其他)
- 用于数据分析的 Python&可视化(Pandas,Matplotlib,Seaborn)
希望你也会发现它们有用!现在欣赏:D 的文章
介绍
信不信由你,在 2022 年仍然有公司雇佣外部数据顾问使用小的 Python 脚本来执行需要最小努力的任务(甚至对于新手)。
“…到 2022 年,仍然会有公司雇佣外部数据顾问来执行任务,这些任务只需使用一个小的 Python 脚本就能轻松完成。”
有趣的是,同样的顾问假装使用一些黑魔法来完成简单的工作,并收取令人难以置信的高费用。这笔钱绝对可以更明智地投资。
例如,想象一下这个场景:一个大型销售团队每个月必须合并来自不同部门的多个 CSV 或 Excel 文件,以创建一个统一的绩效报告。
尽管这些文件通常具有相似的格式,但有时它们非常大,以至于手动复制和粘贴甚至不是一个选项,还可能导致错误或丢失数据。
如果这听起来很熟悉,并且您希望学习如何使用 Python 来自动化这些任务,那么您就来对地方了!
实际上,在这个简短的教程中,我将向您展示如何用最少的 Python 代码将大型 CSV 或 Excel 文件合并成一个文件,甚至不用打开任何原始文件。
所以请继续关注,在这篇文章的结尾,我将与您分享一些额外的内容。
资料组
在文件夹中,您将找到 CSV 格式的 5 个模拟销售文件 ,我将在本教程的下一步中使用它们。
每个文件都正好包括一百万行,并且具有相同数量的列。例如,如果您打开sales_recors_n1.csv
文件,您将会遇到以下格式:
sales_records_n1.csv file.
中前 20 行的示例
一旦你将文件下载到你的笔记本电脑上的一个特定目录,它的内容可以使用os
Python 包中的listdir()
方法列出。
这个方法,要求你把准确的path
传递到目录,如下所示:
import ospath = “/Users/anbento/Documents/sales/sales_csv/”os.listdir(path)**Out[1]:**['sales_records_n5.csv',
'sales_records_n4.csv',
'sales_records_n1.csv',
'sales_records_n3.csv',
'sales_records_n2.csv']
注意这个方法如何返回一个 Python 列表,其中包含了sales_csv
目录中的所有文件。这是有利的,因为对象可以用于迭代读取文件。
# 1 合并多个 CSV 文件
第一步的目标是使用 Python 将 5 个 CSV 文件合并到一个包含 500 万行的独特数据集中。为了做到这一点,我将利用os
和pandas
包。
实现这一点的完整 Python 脚本如下:
现在,让我一步一步地解释代码中发生了什么:
**1。**首先,我正在导入所需的 Python 包,并将path
指定给 CSV 文件。我建议您将所有想要合并的 CSV 文件保存在同一个文件夹中。这会让你的生活更轻松。
**2。然后,我通过将path
附加到每个遵循特定命名约定的文件上来创建一个file_list
(在本例中是所有以 sales_records_n
开头的文件)。根据名称选择文件有时很重要,因为您的工作目录可能还包含许多不相关的文件。注意列表理解是如何被用来生成file_list
的。
这是我打印file_list
内容时得到的结果:
print(file_list)**Output:**['/Users/anbento/Documents/sales/sales_csv/sales_records_n5.csv', '/Users/anbento/Documents/sales/sales_csv/sales_records_n4.csv', '/Users/anbento/Documents/sales/sales_csv/sales_records_n1.csv', '/Users/anbento/Documents/sales/sales_csv/sales_records_n3.csv', '/Users/anbento/Documents/sales/sales_csv/sales_records_n2.csv']
现在,所有文件都附带了路径,可以解析了。
然而,请记住这个列表是无序的,所以如果用来合并文件的顺序对你来说很重要,你将需要在遍历列表时使用函数。
**3。**此时,我首先创建一个空的csv_list
。然后,我用 pandas 的read_csv()
方法迭代解析file_list
中的每个 CSV 文件,并将这些数据集附加到csv_list
。
请注意,当read_csv()
用于解析 CSV 时,数据集被自动转换为 pandas df,因此csv_list
现在包括 5 个单独的 pandas df。但是,在解析文件的同时,我还链接了以下命令:
assign(File_Name = os.path.basename(file))
这是在每个 DF 中创建了一个新的列,其中的包含了原始 CSV 文件的名称,这样,一旦文件被合并,您将确切地知道哪个文件来自哪个文件。
**4。**通过在csv_list
上应用concat()
方法,文件最终被合并成一个唯一的csv_merged
熊猫 DF。添加ignore_index = True
意味着将为csv_merged
生成一个全新的有序索引。
**5。**最后一步是将csv_merged
从 pandas DF 转换回 CSV 文件(名为sales_records_full.csv
),该文件位于同一目录。这是通过to_csv()
命令实现的。在这种情况下,index=False
意味着不应添加包含索引的列。
这就是了!你现在应该看到合并后的文件(包括附加栏 File_Name
)出现在目录中:
os.listdir(path)**Output:**['sales_records_full.csv',
'sales_records_n1.csv',
'sales_records_n2.csv',
'sales_records_n3.csv',
'sales_records_n4.csv',
'sales_records_n5.csv']
除去包导入,只需要 7 行代码和几秒钟的运行时间就可以达到这个结果。
# 2 合并多个 Excel 文件
但是如果您希望合并大的 Excel 文件呢?
代码的差异很小:您只需在解析文件时用read_excel()
替换方法read_csv()
,在将sales_records_full.xlsx
写回目录时用to_excel()
替换to_csv()
。
包括上述变化的完整 Python 脚本如下:
如果你想边做边学,我建议你下载其他文件夹中的文件。运行代码后,您应该会获得类似于以下内容的合并文件:
sales_records_full.xlsx file
中前 20 行的示例
正如你所看到的,独立于你的文件的扩展名,过程是完全一样的,只要你能把文件转换成 pandas DFs。
# 3 好处:将大文件分割成小文件
如果你一直读到教程的这一点,你应该得到一些额外的内容!
例如,现在让我们假设你正面临着与目前所描述的相反的问题:
您正在处理一个包含 500 万行的非常大的 CSV 或 Excel 文件,并且您希望将它拆分成多个较小的文件,这样您就可以更快地打开它们并显示它们的内容。怎么做呢?
这是另一个简单的任务,因为您可以简单地用read_csv()
方法读取原始 CSV 文件,以 dataframe 格式(df
)保存它,然后对行索引使用切片——比方说——将第一个 1M 行选择到一个更小的df_1
DF 中。
可以重复该过程以生成多个较小的文件,如下所示:
结论
在这篇简短的教程中,我展示了使用 Python 将多个大文件合并成一个唯一文件是多么直观。
一种可能的策略(本文中描述的策略)是简单地将它们转换成 pandas 文件,然后将它们连接起来,生成一个独特的文件。
这个过程是与扩展名无关的,前提是文件可以用 pandas 解析,并且总共只需要 7 行代码,这使得它成为刚刚学习用 Python 编程的人自动化的绝佳候选。
但是你呢?你知道在 Python 中合并多个文件的其他更有效的方法吗?欢迎在评论中分享你的知识,😄
你可能也喜欢
</10-algorithms-to-solve-before-your-python-coding-interview-feb74fb9bc27> 💔-ways-to-compute-a-weighted-average-in-python-4e066de7a719> 💔-ways-to-iterate-over-python-dictionaries-using-for-loops-14e789992ce5>
给我的读者一个提示
这个帖子包括附属链接,如果你购买的话,我可以免费给你一点佣金。
如何合并熊猫数据帧
原文:https://towardsdatascience.com/how-to-merge-pandas-dataframes-221e49c41bec
对熊猫数据帧执行左、右、内和反连接
安德斯·吉尔登在 Unsplash 上拍摄的照片
介绍
通常,我们可能必须将 pandas 数据帧合并在一起,以便基于最终服务于我们正在进行的任务的目的的一些逻辑,构建包含来自相关方的列和行的新数据帧。
在今天的文章中,我们将展示如何合并熊猫数据帧,并执行LEFT
、RIGHT
、INNER
、OUTER
、FULL
和ANTI
连接。Pandas 合并相当于 SQL 中的连接,我们将采用 SQL 风格的方法来解释合并,因为这将有助于新来者跟上。更具体地说,我们将展示如何表演
- 左连接(也称为左外连接)
- 右连接(也称为右外连接)
- 内部连接
- 完全外部连接
- 左反连接(又名左排除连接)
- 右反联接(又名右排除联接)
- 完全反联接
除了不同的连接/合并类型,在下面的部分中,我们还将介绍如何
- 在单个列上合并(在两个 dfs 上具有相同的名称)
- 在多列上合并
- 合并不同名称的列
- 重命名联接中使用的共有列名
- 仅从联接所涉及的数据框架中选择一些列
首先,让我们创建几个将在本教程中使用的数据框架,以演示我们今天将讨论的各种连接类型。
import pandas as pd df1 = pd.DataFrame(
[
(1, 345, 'B', True),
(2, 100, 'C', False),
(3, 300, 'B', False),
(4, 151, 'A', False),
(5, 212, 'A', True),
(6, 121, 'C', False),
(7, 333, 'B', True),
(8, 456, 'C', True),
],
columns=['id', 'value', 'colC', 'colD']
)df2 = pd.DataFrame(
[
(1, 111, 10.1, 3),
(9, 56, 3.33, 10),
(10, 17, 18.0, 8),
(3, 567, 19.1, 4),
(11, 98, 2.1, 1),
(6, 31, 3.14, 12),
],
columns=['id', 'value', 'colE', 'colF']
)print(df1)
***id value colC colD*** *0 1 345 B True
1 2 100 C False
2 3 300 B False
3 4 151 A False
4 5 212 A True
5 6 121 C False
6 7 333 B True
7 8 456 C True*print(df2)
***id value colE colF*** *0 1 111 10.10 3
1 9 56 3.33 10
2 10 17 18.00 8
3 3 567 19.10 4
4 11 98 2.10 1
5 6 31 3.14 12*
内部连接
两个 pandas 数据帧之间的内部连接将产生一组记录,这些记录在指定的连接列中具有共同的值。
内部连接:使用两个帧的关键点的交集
对两个数据帧执行内部连接时选择的记录—来源:作者
为了使用单个列在两个数据帧之间执行内部连接,我们只需要在调用merge()
时提供on
参数。
df1.merge(df2, on='id')
注意,默认情况下,[merge()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.merge.html)
方法执行内部连接(how='inner'
),因此您不必显式指定连接类型。输出将包含在df1
和df2
中具有共同 id 的所有记录:
***id value_x colC colD value_y colE colF*** *0 1 345 B True 111 10.10 3
1 3 300 B False 567 19.10 4
2 6 121 C False 31 3.14 12*
左连接(也称为左外连接)
左联接(或左外联接)将在指定的联接列上,从左数据帧中取出所有记录,以及从右数据帧中取出与左数据帧具有匹配值的记录。
结果中包含的右侧数据帧记录中的任何缺失值将被替换为NaN
。
左侧外部连接:仅使用左侧帧中的关键点
对两个数据帧执行左连接时选择的记录-来源:作者
要在两个熊猫数据帧之间执行左连接,现在需要在调用merge()
时指定how='left'
。
df1.merge(df2, on='id', how='left')
如上所述,得到的数据帧将包含左侧数据帧中的每条记录,以及右侧数据帧中与连接列匹配的这些记录的相应值。这些记录的结果中与右侧数据帧中的记录不匹配的其余列值将被替换为NaN
s。
***id value_x colC colD value_y colE colF*** *0 1 345 B True 111.0 10.10 3.0
1 2 100 C False NaN NaN NaN
2 3 300 B False 567.0 19.10 4.0
3 4 151 A False NaN NaN NaN
4 5 212 A True NaN NaN NaN
5 6 121 C False 31.0 3.14 12.0
6 7 333 B True NaN NaN NaN
7 8 456 C True NaN NaN NaN*
右连接(也称为右外连接)
右联接(或右外联接)将在指定的联接列上,从右数据帧中取出所有记录,以及从左数据帧中取出与右数据帧具有匹配值的记录。
包含在结果中的左侧数据帧记录中的任何缺失值将被替换为NaN
。
右侧外部连接:仅使用右侧帧中的关键点
对两个数据帧执行右连接时选择的记录-来源:作者
要在两个熊猫数据帧之间执行左连接,现在需要在调用merge()
时指定how='right'
。
df1.merge(df2, on='id', how='right')
df1
和df2
数据帧之间右连接的结果如下所示。
***id value_x colC colD value_y colE colF*** *0 1 345.0 B True 111 10.10 3
1 9 NaN NaN NaN 56 3.33 10
2 10 NaN NaN NaN 17 18.00 8
3 3 300.0 B False 567 19.10 4
4 11 NaN NaN NaN 98 2.10 1
5 6 121.0 C False 31 3.14 12*
完全外部连接
完整的外部连接基本上包括来自左右数据帧的所有记录。这种类型的连接将使用两个帧中的键——对于任何缺失的行,将插入NaN
值。
完全外部连接:使用两个帧的键的联合
对两个数据帧执行完全外部连接时选择的记录—来源:作者
要在两个 pandas 数据帧之间执行完整的外部连接,现在需要在调用merge()
时指定how='outer'
。
df1.merge(df2, on='id', how='outer')
使用我们的两个示例框架的完整外部连接的输出如下所示。
***id value_x colC colD value_y colE colF*** *0 1 345.0 B True 111.0 10.10 3.0
1 2 100.0 C False NaN NaN NaN
2 3 300.0 B False 567.0 19.10 4.0
3 4 151.0 A False NaN NaN NaN
4 5 212.0 A True NaN NaN NaN
5 6 121.0 C False 31.0 3.14 12.0
6 7 333.0 B True NaN NaN NaN
7 8 456.0 C True NaN NaN NaN
8 9 NaN NaN NaN 56.0 3.33 10.0
9 10 NaN NaN NaN 17.0 18.00 8.0
10 11 NaN NaN NaN 98.0 2.10 1.0*
左反连接(又名左排除连接)
左反连接将包含左框架中键没有出现在右框架中的所有记录。
左侧反连接:仅使用左侧帧中不出现在右侧帧中的关键点
对两个数据帧执行左反连接时选择的记录—来源:作者
熊猫的左反加入可以分两步进行。第一步,我们需要用indicator=True
执行一个左外连接:
指标
*bool*
或*str*
,默认*False*
如果是
True
,在输出数据帧中添加一个名为'_merge'
的列,其中包含每行的源信息。通过提供字符串参数,可以为该列指定一个不同的名称。对于合并键仅出现在左侧数据帧中的观察,该列将具有值为'left_only'
的Categorical
类型;对于合并键仅出现在右侧数据帧中的观察,该列将具有值为'right_only'
的类型;如果观察的合并键同时出现在两个数据帧中,则该列将具有值为'both'
的类型。— Python 文档
df1.merge(df2, on='id', how='left', indicator=True) ***id value_x colC colD value_y colE colF _merge*** *0 1 345 B True 111.0 10.10 3.0 both
1 2 100 C False NaN NaN NaN left_only
2 3 300 B False 567.0 19.10 4.0 both
3 4 151 A False NaN NaN NaN left_only
4 5 212 A True NaN NaN NaN left_only
5 6 121 C False 31.0 3.14 12.0 both
6 7 333 B True NaN NaN NaN left_only
7 8 456 C True NaN NaN NaN left_only*
在第二步中,我们只需要query()
上一个表达式的结果,以便只保留来自左侧框架的行,并过滤掉那些也出现在右侧框架中的行。
如果我们将这两个步骤结合在一起,得到的表达式将是
df1.merge(df2, on='id', how='left', indicator=True) \
.query('_merge == "left_only"') \
.drop('_merge', 1)
以及相应的结果
***id value_x colC colD value_y colE colF*** *1 2 100 C False NaN NaN NaN
3 4 151 A False NaN NaN NaN
4 5 212 A True NaN NaN NaN
6 7 333 B True NaN NaN NaN
7 8 456 C True NaN NaN NaN*
右反联接(又名右排除联接)
类似地,右反连接将包含右框架的所有记录,这些记录的键没有出现在左框架中。
右侧反连接:仅使用右侧帧中不出现在左侧帧中的关键点
对两个数据帧执行右反连接时选择的记录—来源:作者
熊猫的右反加入可以分两步进行。第一步,我们需要用indicator=True
执行一个右外连接:
指示器
*bool*
或*str*
,默认*False*
如果是
*True*
,则向输出数据帧添加一个名为*'_merge'*
的列,其中包含每行的源信息。通过提供字符串参数,可以为该列指定一个不同的名称。对于合并关键字只出现在左侧数据帧中的观察,该列将具有值为*'left_only'*
的Categorical
类型;对于合并关键字只出现在右侧数据帧中的观察,该列将具有值为*'right_only'*
的类型;如果观察的合并关键字同时出现在两个数据帧中,则该列将具有值*'both'*
。— Python 文档
df1.merge(df2, on='id', how='right', indicator=True) ***id value_x colC colD value_y colE colF _merge*** *0 1 345.0 B True 111 10.10 3 both
1 9 NaN NaN NaN 56 3.33 10 right_only
2 10 NaN NaN NaN 17 18.00 8 right_only
3 3 300.0 B False 567 19.10 4 both
4 11 NaN NaN NaN 98 2.10 1 right_only
5 6 121.0 C False 31 3.14 12 both*
在第二步中,我们只需要query()
上一个表达式的结果,以便只保留来自右帧的行,并过滤掉那些同时出现在左帧中的行。
如果我们将这两个步骤结合在一起,得到的表达式将是
df1.merge(df2, on='id', how='right', indicator=True) \
.query('_merge == "right_only"') \
.drop('_merge', 1)
使用我们的示例数据帧得到的帧将是
***id value_x colC colD value_y colE colF*** *1 9 NaN NaN NaN 56 3.33 10
2 10 NaN NaN NaN 17 18.00 8
4 11 NaN NaN NaN 98 2.10 1*
完全反联接
完整的反连接将包含没有任何公共键的左帧和右帧的所有记录。
完全反连接:取两帧密钥的对称差
对两个数据帧执行完全反连接时选择的记录—来源:作者
同样,这可以像我们讨论的前两种反连接类型一样分两步执行。
df1.merge(df2, on='id', how='outer', indicator=True) \
.query('_merge != "both"') \
.drop('_merge', 1)
使用我们的示例帧的结果如下所示。
***id value_x colC colD value_y colE colF*** *1 2 100.0 C False NaN NaN NaN
3 4 151.0 A False NaN NaN NaN
4 5 212.0 A True NaN NaN NaN
6 7 333.0 B True NaN NaN NaN
7 8 456.0 C True NaN NaN NaN
8 9 NaN NaN NaN 56.0 3.33 10.0
9 10 NaN NaN NaN 17.0 18.00 8.0
10 11 NaN NaN NaN 98.0 2.10 1.0*
更改同名列的后缀
还要注意如何分别使用_x
和_y
自动重命名同名的列。您可以通过向suffixes
参数提供所需的值来更改默认值。举个例子,
df1.merge(df2, on='id', **suffixes=('_df1', '_df2'**))
现在,参与连接的左右数据帧中的每一列都将具有指定的后缀。
**id value_df1 colC colD value_df2 colE colF** *0 1 345 B True 111 10.10 3
1 3 300 B False 567 19.10 4
2 6 121 C False 31 3.14 12*
合并不同的列名
现在让我们考虑另一个用例,其中我们想要合并两个 pandas 数据帧的列没有相同的名称。在这种情况下,我们不提供on
参数,而是必须提供left_on
和right_on
参数来指定在将左右数据帧合并在一起时要考虑的列。
作为一个例子,假设我们想要分别基于id
和colF
列合并df1
和df2
。以下命令将完成这一任务:
df1.merge(df2, left_on='id', right_on='colF')
得到的数据帧如下所示
***id_x value_x colC colD id_y value_y colE colF***
*0 1 345 B True 11 98 2.1 1
1 3 300 B False 1 111 10.1 3
2 4 151 A False 3 567 19.1 4
3 8 456 C True 10 17 18.0 8*
在多列上合并
如果您想要合并多个列,您可以简单地将所有想要的列作为一个列表传递到on
参数中:
df1.merge(df2, on=['colA', 'colB', ..])
如果左框架和右框架中的列有不同的名称,那么您可以再次使用right_on
和left_on
参数:
df1.merge(df2, left_on=['colA', 'colB'], right_on=['colC', 'colD])
从所涉及的数据帧中仅选择一些列
现在假设我们想使用左外连接将框架df1
和df2
合并在一起,选择df1
中的所有列,但只选择df2
中的列colE
。
为此,在将帧传递给merge()
方法时,可以简单地使用df2
列的子集。
df1.merge(df2[['id', 'colE']], on='id')
这将从右侧框架中排除除colE
之外的所有列:
***id value colC colD colE*** *0 1 345 B True 10.10
1 3 300 B False 19.10
2 6 121 C False 3.14*
最后的想法
在本教程中,我们讨论了合并熊猫数据帧以及如何执行左外、右外、内、全外、左反、右反和全反连接。
此外,我们还讨论了一些其他用例,包括如何连接不同名称的列,甚至是多个列。此外,我们还展示了如何更改具有相同名称的列名的后缀,以及如何在执行合并后只从左侧或右侧数据帧中选择列的子集。
每当你想在熊猫数据帧之间执行一些连接时,你可以使用这篇文章作为备忘单,因此可以自由地保存这篇文章或在你的浏览器上创建一个书签!
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
相关文章你可能也喜欢
[## 熊猫中的 loc 与 iloc
towardsdatascience.com](/loc-vs-iloc-in-pandas-92fc125ed8eb)
如何合并熊猫数据帧
原文:https://towardsdatascience.com/how-to-merge-pandas-dataframes-35afe8b1497c
如何避免丢失有价值的数据点(包括备忘单)
合并的熊猫(图片由作者提供)
合并两个数据帧时的一个常见陷阱是无意中丢失了有价值的数据点。有时,您需要用第二个数据集中的附加信息来扩展您的初始数据集。为此,您可以将两个数据集读入 pandas 数据帧,然后用.merge()
方法将它们组合成一个数据帧。但是,根据您合并它们的方式,您最终可能会得到比预期更少或更多的数据点。
但是,根据您合并它们的方式,您最终可能会得到比预期更少或更多的数据点。
本文将介绍合并两个数据帧的四种最常见的方法。由于合并 pandas 数据帧类似于 SQL 连接,我们将使用它们作为类比[1]。也就是说,我们将展示如何进行:
- 左外部联接(熊猫:“左”)
- 右外部联接(熊猫:“右”)
- 完全外部连接(熊猫:“外部”)
- 内部联接(熊猫:“内部”)
此外,我们将向您展示如何验证您的结果。
基本原则
为了解释这些概念,我们将使用下面两个最小的虚构数据集。在这个例子中,我们为动物园中的熊猫准备了两张桌子。第一个表包含动物园的位置信息。第二个表包含关于哪只熊猫在哪个动物园的信息。
左侧数据帧 df1(蓝色)和右侧数据帧 df2(黄色)(图片由作者提供)
在下面的例子中,数据帧被着色以说明哪个条目来自哪个数据帧。当合并两个数据帧时,您将它们称为“左”和“右”数据帧。在本例中,df1
是左边的数据帧,颜色为蓝色。df2
是右边的数据框,用黄色标出。如果合并的数据帧中的一个条目来自两个数据帧,它将用绿色行背景指示。
- 左侧数据框:
df1
,以蓝色着色 - 右侧数据框:
df2
,用黄色着色 - 关键列:合并
df1
和df2
的公共列。在本例中,键列是“zoo_id”。 - 合并的数据帧:
df_merged
,左边的行为蓝色,右边的行为黄色,右边的行为绿色
让我们来看看.merge()
方法及其必要参数。这种方法比下面讨论的参数更多。然而,我们将只涉及与本文相关的内容。您可以参考文档[2]了解更多参数。
DataFrame.merge(right,
how = "...",
on = None,
indicator = False,
...)
首先,从左边的数据帧df1
调用.merge()
方法,第一个参数是右边的数据帧df2
。
df_merged = df1.merge(df2)
您也可以合并两个数据帧,如下所示,其中第一个参数是左侧数据帧,第二个参数是右侧数据帧:
df_merged = pd.merge(df1, df2)
虽然.merge()
方法足够智能,可以找到要合并的公共键列,但我建议用参数on
显式定义它。这不仅让你的代码可读性更好,还加快了执行时间。
df_merged = df1.merge(df2,
on = "zoo_id")
如果键列在两个数据帧中没有相同的名称,可以使用参数on_left
和on_right
代替on
。
df_merged = df1.merge(df2,
on_left = "key1",
on_right = "key2")
为了指示合并的数据帧中的一行来自哪个数据帧,我们将使用参数indicator = True
。该选项将在合并的数据框架中创建一个新列“_merge”,如下例所示。对于合并数据帧的常规用法,可以省略 **indicator**
参数。
完全外部连接(熊猫:“外部”)
如果你想拍下每只熊猫和每个动物园的全景,该怎么办?
完全外部连接(图片由作者提供)
为此,您可以在 SQL speak [1]中使用完整的外部连接。
SELECT *
FROM df1
**FULL OUTER JOIN** df2
ON df1.zoo_id = df2.zoo_id;
在熊猫身上,你可以使用how = "outer"
【2】。
df_merged = df1.merge(df2,
on = "zoo_id",
how = **"outer"**,
indicator = True)
下面,您可以看到通过键列匹配两个数据框中每一行的各种可能性。值 101、102 和 103 出现在两个数据帧的两个键列中。如果两个数据帧都匹配,则在两个数据帧的相交处会出现一个绿点。
然而,值 104 仅出现在左侧数据帧的关键字列中,而值 105 仅出现在右侧数据帧的关键字列中。不匹配的行在与称为“不匹配”的线的相交处分别用蓝色或黄色点表示。
完整的外部联接包含下图中的所有点。
如果你想拍下每只熊猫和每个动物园的全景,该怎么办?
DataFrame 与“外部”合并(图片由作者提供)
作为健全性检查,合并数据帧的预期长度应该大于或等于较长数据帧的长度。合并的数据帧df_merged
总共有七行:如列_merge
所示,两个都有四行,一个只从左边,两个只从右边。
绿色行不包含空值,而蓝色和黄色行包含缺失值。由于绿色行来自两个数据帧,因此每列都有一个值。然而,因为左边的数据帧df2
不包含任何与zoo_id = 104
一起生活在动物园中的熊猫,所以第 4 行的列panda_name
是 nan。黄色的第 5 行和第 6 行也是如此,因为df1
不包含任何关于带有zoo_id = 105
的动物园的信息。
内部联接(熊猫:“内部”)
但是,如果你只想看看饲养熊猫的动物园呢?
内部连接(图片由作者提供)
为此,您可以在 SQL speak [1]中使用内部连接。
SELECT *
FROM df1
**INNER JOIN** df2
ON df1.zoo_id = df2.zoo_id;
在熊猫身上,你会用how = "inner"
【2】。
df_merged = df1.merge(df2,
on = "zoo_id",
how = **"inner"**,
indicator = True)
在下图中,您可以再次看到完全外部连接所描述的匹配。但是,内部连接只考虑绿点,这表示两个数据帧的两个键列中都存在一个值。不匹配的值(完全外部连接中的蓝色和黄色点)被排除在外,如上图所示。
但是,如果你只想看看饲养熊猫的动物园呢?
DataFrame 与“inner”合并(图片由作者提供)
作为健全性检查,合并数据帧的预期长度应该**长于或等于较短数据帧的长度。**合并的数据帧df_merged
总共有四行:如列_merge
中所示,两者都有四行。
左外部联接(熊猫:“左”)
现在,假设您想知道每个动物园都有哪些熊猫。有了这些信息,你可以计算出每个动物园有多少只熊猫。
左外部连接(图片由作者提供)
为此,您可以在 SQL speak [1]中使用左外连接。
SELECT *
FROM df1
**LEFT OUTER JOIN** df2
ON df1.zoo_id = df2.zoo_id;
在熊猫身上,你可以用how = "left"
【2】。
df_merged = df1.merge(df2,
on = "zoo_id",
how = **"left"**,
indicator = True)
在下图中,您可以再次看到完全外部连接所描述的匹配。然而,左外连接只考虑绿点和蓝点,如上图所示。右侧数据框中不匹配的值(完全外部连接中的黄点)将被排除。
假设您想要计算每个动物园有多少只熊猫。
DataFrame 与“左”合并(图片由作者提供)
作为健全性检查,合并数据帧的预期长度应**长于或等于左侧数据帧的长度。**合并的数据帧df_merged
总共有 5 行:如列_merge
所示,两边各 4 行,左边 1 行。
右外部联接(熊猫:“右”)
最后,假设您想知道每只熊猫生活在哪个动物园。
右外部连接(图片由作者提供)
为此,您可以在 SQL speak [1]中使用右外连接。
SELECT *
FROM df1
**RIGHT OUTER JOIN** df2
ON df1.zoo_id = df2.zoo_id;
在熊猫身上,你可以用how = "right"
【2】。
df_merged = df1.merge(df2,
on = "zoo_id",
how = **"right"**,
indicator = True)
在下图中,您可以再次看到完全外部连接所描述的匹配。然而,一个右外连接只考虑绿色和黄色的点,如上面的 panda Venn 图所示。左侧数据框中不匹配的值(完全外部连接中的蓝点)将被排除。
假设您想知道每只熊猫生活在哪个动物园。
DataFrame 与“右”合并(图片由作者提供)
作为健全性检查,合并的数据帧的预期长度应该比右数据帧的长度长或等于右数据帧的长度**。**合并后的数据帧df_merged
总共有六行:如_merge
列所示,四行来自两边,两行仅来自右边。
结论
这篇文章(字面上)演示了如何用.merge()
方法合并两个熊猫数据帧。也就是说,我们研究了如何在 pandas 中执行最常见的 SQL 连接类型:全外部连接、内部连接、左外部连接和右外部连接。
下面你可以找到这篇文章的直观摘要:
如何合并熊猫数据帧的备忘单(图片由作者提供)
喜欢这个故事吗?
要阅读更多来自我和其他作家的故事,请在 Medium 上注册。报名时可以用我的 推荐链接 支持我。我将收取佣金,不需要你额外付费。
https://medium.com/@iamleonie/membership
在LinkedIn和 上找我 Kaggle !
参考
[1]“熊猫 1.4.2 文档”,“与 SQL 的比较。”pandas.pydata.org。https://pandas . pydata . org/docs/getting _ started/comparison/comparison _ with _ SQL . html # join(2022 年 7 月 13 日访问)
[2]“pandas 1 . 4 . 2 文档”,“pandas . data frame . merge .”pandas.pydata.org。https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.merge.html(2022 年 7 月 13 日访问)
如何测试你的人工智能系统
原文:https://towardsdatascience.com/how-to-mess-up-testing-your-ai-system-36d97ec56fe7
避免典型的数据科学新手错误
当与机器学习(ML) 和人工智能(AI) 一起工作时,保持头脑清醒的一个好方法是像老师一样思考。毕竟, ML/AI 的重点是你让你的(机器)学生通过给出例子而不是明确的指令来学习一项任务。
正如任何老师都会提醒你的:如果你想用例子来教学,例子必须是好的。任务越复杂,你需要的例子就越多。如果你想相信你的学生已经学会了这个任务,测试必须是好的。
由 Husniati Salma 在 Unsplash 上拍摄的照片
如果你想用例子来教学,例子必须是好的。如果你想信任你的学生,测试必须是好的。
这就是为什么测试在 ML/AI 中极其重要,但不幸的是这并不总是容易的。让我们来看看两种使测试变得一团糟的经典方法:一种是初学者的错误,另一种更阴险一些——大多数从业者至少已经上当一次了。
初学者犯的错误
想象一下,我正计划训练一个人工智能图像识别系统来对香蕉的照片以及我的两只猫赫胥黎和特斯拉的照片进行分类。
由于从头开始构建一个图像识别系统需要数千张照片,所以上面七张图像中的每一张都是 10,000 张类似照片的占位符。
我们将把这 70,000 张图像输入到一个人工智能算法中,并训练我们的模型。我们看到了相当不错的培训表现,但是我们的解决方案真的有效吗?
我们不知道,直到我们测试它…所以我们来测试一下吧!
注意到我们选择的 60,000 张测试图片有什么问题吗?
他们看起来非常眼熟,不是吗?也许我们在哪里见过他们?
忽略我们内心的警钟,我们将提交它们而不贴标签,看看我们的系统是否已经学会应用正确的标签。瞧,它以 100% 的准确率执行任务!
没有任何测试错误…所以我们没有任何问题,对不对?这个系统是 100%可信的吧?不对!
知道我们的系统是否值得信赖的唯一方法是检查它是否能够应对相关的新情况,而这与我们所做的正好相反。我们只给了它旧的数据。那里有 60,000 个错误!我们应该更清楚地知道不要重复使用我们的训练数据,但因为我们搞砸了我们的测试程序,我们的人工智能解决方案可能只是记住了它的胜利之路。
我们刚刚做的是用人类大学生已经看过的例子来测试他们的机器等价物。我们怎么知道他们没有记住答案?我们没有。像这样的考试绝对没有证据表明我们的学生能够概括并在未来的例子中表现良好……这是机器学习的全部意义,而不是机器通过查找表记忆(你不需要 ML/AI 来做这件事)。
记忆的麻烦在于它只对过去有效,对未来无效。
无论你认为用人类学生已经看过的例子来测试他们是多么愚蠢,机器学生的情况更糟。由于机器学习和人工智能解决方案的复杂性,如果没有原始的、未使用的数据集,很难检测到过度拟合和记忆。计算机对数据有非常好的记忆力——这就是它们的用途。我的电脑已经记住了你现在正在读的文章的每一个字,而你可怜的作者甚至不能在文章发表 5 分钟后再现它。
由于机器学习和人工智能解决方案的复杂性,如果没有原始的、未使用的数据集,很难检测到过度拟合和记忆。
如果你允许的话,计算机当然可以记住它们找到完美解决方案的方法。唉,记忆的麻烦在于它只对过去有效,对未来无效。如果我们只对过去感兴趣,我们就不会使用机器学习。(此处解释。)
由于机器学习和人工智能解决方案的复杂性,如果没有原始的、未使用的数据集,很难检测到过度拟合和记忆。在我的课程中了解更多:http://bit.ly/mfml_049
当你建立机器学习解决方案时,你的目标是你能得到的最忠实和准确的未来模拟器。
这就是为什么一个更好的测试集应该是由系统不可能记住的例子组成的。换句话说,全新的数据。这是对未来数据的更准确的模拟…你的目标是你能得到的最忠实和准确的未来模拟。让我们用 40,000 张新图片进行测试吧!
我们表现如何?
从技术上来说,事情将会变得非常糟糕,因为这个类是少数。在像我们这样不平衡的数据集中,你更有可能看到所有东西都被贴上多数标签的失败。或者随机标签。但是香蕉是一个有趣的词,所以请原谅我。
原来我们的制度就是一堆臭垃圾。提示悲伤的长号!
因为我们使用新数据进行测试,所以系统无法通过过度拟合和记忆来作弊,所以我们能够发现它的真实性能(或缺乏性能)。
揭开我们的零
顺便说一句,0% 准确率作为分数很诡异。一个由 70,000 个可靠的相关训练图像组成的数据集掌握在专家手中,不太可能导致如此糟糕的测试性能。鉴于目前可用的工具,特别是如果你使用云提供商的人工智能解决方案,如谷歌云的 AutoML Vision ,你必须非常努力地尝试才能做得如此糟糕。
在测试数据中获得 0%通常意味着在训练我们的系统时,除了无辜的“我们真的有”*no-*idea-what-we-being-that-training-our-system 之外,还有一些错误。像 0%这样的精度实际上很难达到。你不太可能遇到这些情况,因为即使是随机猜测也会给你比 0%更好的结果,当你的数据中没有有用的模式时,随机猜测是许多算法默认的。这表明出现了灾难性的错误,至少像输入的测试数据集与训练集的格式或领域不同一样糟糕。比如尝试输入你的纳税申报表的截图,而不是 4 万张猫的照片。
我告诉你这些不是因为你需要知道如何处理 0%类型的结果(检查测试集的源、元数据和模式),而是因为获得比零更好的性能是标准的。这不是你的项目好运的预兆,也不是庆祝你的未孵化小鸡的理由;真正的胜利是一个分数超过了合理的预定基准,通常这个数字至少比随机猜测要好一点。
避免新手的错误
确保你总是在原始的数据上测试,并且从来没有被 ML/AI 系统或者构建它的团队看到过。这就是你如何避免过度拟合的方法,你可以把这种情况想象成学生记住了考试的问题和答案。
总是使用原始数据进行测试。
为了确保您在原始数据上进行测试,周围必须有原始数据。你是怎么得到它的?一种方法是做出坚定的承诺——包括预算和计划!—在未来收集更多数据…这有时说起来容易做起来难。如果你不断有新的数据流入,你应该感到幸运,对于我们这些为拥有面向用户应用的公司工作的人来说,这是一种太容易被视为理所当然的特权;不是每个人都有这样丰富的数据。
照片由 Unsplash 上的 regularguy.eth 修改而来
如果你不能在需要的时候廉价地收集大量数据,那就养成在每个项目开始时解决测试问题的习惯,方法是分割你的数据并将其中一些数据锁起来,直到对你的数据解决方案的性能进行最终统计评估的时候。不幸的是,许多其他方面值得尊敬的公司和团队搬起石头砸了自己的脚,因为他们未能分割数据,然后测试他们的训练数据,推出垃圾系统,并为他们的错误付出高昂的代价。
即使新数据丰富且易于收集,我也不会过分强调组织通过良好的数据访问策略建立健康的数据文化的重要性,因此改善数据科学实践的最佳和最快的快速解决方案之一是让团队中的每个人都了解数据拆分的重要性。
数据领导者不是要求每个新手做正确的事情,而是通过将数据分割设计到您的数据访问策略中,或者更好的是,如果您已经运行了一个具有定制基础架构的大型团队,则设计到您的数据科学工具中,从而使他们不可能做错误的事情。
专家犯的错误
现在我们已经讨论了新手的错误,我们已经准备好处理专家的错误,你可以在本系列的第 2 部分中找到:
https://kozyrkov.medium.com/the-mistake-every-data-scientist-has-made-at-least-once-3479002211b4
感谢阅读!YouTube 课程怎么样?
如果你在这里很开心,并且你正在寻找一个为初学者和专家设计的有趣的应用人工智能课程,这里有一个我为你制作的课程:
在这里欣赏整个课程播放列表:【bit.ly/machinefriend
喜欢作者?与凯西·科兹尔科夫联系
让我们做朋友吧!你可以在 Twitter 、 YouTube 、 Substack 和 LinkedIn 上找到我。有兴趣让我在你的活动上发言吗?使用表格取得联系。
有兴趣尝试图像分类吗?
从这里开始使用 Google Cloud Vision API 和 AutoML Vision:
https://bit.ly/googlecloudvision
如何缓解 Python 中的内存问题
原文:https://towardsdatascience.com/how-to-mitigate-memory-issues-in-python-c791b2c5ce7e
一个小窍门,可以节省你的时间、精力和成本。
最近,由于 Python 中管理内存的方式,我遇到了一个问题,在内存受限的环境中使用 Pandas 数据帧和 Numpy 数组可能会变得很严重。这个问题让我花了两天时间,而不是预计的两个小时来实现一个标准的数据处理任务。真扫兴!
因为我们所有的时间都是很昂贵的,所以我写下了我的学习,这样将来的我,也许你可以避免这个问题,节省时间,成本和精力。你准备好了吗?我的故事来了。
故事
我必须使用一个 AWS 弹性容器服务 (ECS)任务在云中处理一堆拼花文件。我想:没有比这更简单的了,我将使用 Pandas 依次加载每个文件,应用我的机器学习模型,保存结果,我就完成了。没什么特别的,只是一个基本的数据处理任务。我的代码大致如下:
import pandas as pd
class Processor:
def run(self, file_names: list[str]) -> None:
for file_name in file_names:
data = pd.read_parquet(file_name)
result = self._process(data)
self._save(result)
现在,要在 ECS 上做到这一点,您必须编写一个 docker 文件,并设置一个 ECS 任务,相应的容器将在其中运行。在那里,您必须指定想要使用多少 CPU 和多少内存。显然,你走得越高,它就变得越贵,你给的钱就越多。由于我的每个文件只有几百兆大,我想我可以选择一个小的大小,因此不必在 AWS 上花费太多。所以我选择了两个 CPU 和 8g 内存。对我来说,考虑到我的数据量,这听起来已经有点夸张了。但我想保险起见,并认为现在可能会出错吗?
问题是
因此,我满怀信心地部署了我的容器,并开始了 ECS 任务。第一个文件已成功加载和处理。是啊。第二个文件已成功加载和处理。是的。第三次、第四次和第五次也是如此,但之后…
Container exited with code 137\. Reason was OutOfMemoryError:
Container killed due to memory usage
斯蒂芬·拉德福德在 Unsplash 上拍摄的照片
什么?我没想到会发生这种事。8 Gb 的内存怎么可能不够处理一个只有几百兆大小的文件?更重要的是,由于每个文件的大小完全相同,为什么这个问题只发生在第六个文件之后,而不是直接发生在第一个文件上?关于 Python 中如何管理内存,肯定有什么地方出错了,或者说是我没有考虑到的地方。
所以,我谷歌了一下 Python 中的内存管理,学习了引用计数和垃圾收集的基础知识。简单来说,引用计数就是计算 python 对象在代码中被主动引用的频率。如果一个对象在任何地方都不再被引用,也就是说,它的引用计数器为零,Python 垃圾收集器可以介入并释放这个对象占用的内存。很好,听起来很琐碎。
无效的解决方案
因此,我认为加强这种行为将解决我的问题,我终于可以完成我的任务。那你做了什么?为了将引用计数器减少到零,我在引用数据的变量上使用了**del**
。为了强制垃圾收集器在那之后立即运行,我显式地使用了来自 gc 模块的**collect**
函数。有了这个,我的更新版本大致如下
import pandas as pd
import gc
class Processor:
def run(self, file_names: list[str]) -> None:
for file_name in file_names:
data = pd.read_parquet(file_name)
result = self._process(data)
self._save(result)
del result
del data
gc.collect()
怀着非常高的希望,我部署了这个更新版本,启动了容器,等待处理第六个文件。猜猜发生了什么?由于内存使用,容器被杀死。
妈的,一点进步都没有*。很明显,在我最基本的代码中还隐藏着一些我无法影响的东西,它们一直占据着我的内存。*
那么我们现在应该做些什么来解决这样一个常见的数据工程问题呢?选择更多的内存并进一步增加杰夫·贝索斯的财富是唯一的出路吗?幸运的是,这个问题的答案是 不是 。有一种方法应该总是有效的,尽管感觉有点粗糙。
工作解决方案
为了确保在一个函数完成后释放内存或其他资源,您所要做的就是在不同的进程中执行该函数。当该进程完成时,操作系统 (OS)释放该进程已经获得的所有资源。这总是独立于底层操作系统工作。需要注意的是,启动一个进程会降低整体性能。
在 Python 的进程中运行函数的一种方式是通过标准的多处理模块。然而,这要求函数及其所有参数都是可选择的。参见这个网站获取可供选择的类型列表。在我的例子中,情况并非如此,因为我想运行一个类的方法,使用默认的 pickle 库是不可选择的。该死的。
幸运的是,有一个名为 loky 的不错的第三方库,它使用了引擎盖下的 cloudpickle 模块,几乎可以腌制任何东西。太好了!
有了这些,我的最终解决方案看起来像
import pandas as pd
import gc
from loky import get_reusable_executor
# I only need one workere as I don't want to do multiprocessing
executor = get_reusable_executor(max_workers=1)
class Processor:
def _execute(self, file_name:str) -> None:
data = pd.read_parquet(file_name)
result = self._process(data)
self._save(result)
def run(self, file_names: list[str]) -> None:
for file_name in file_names:
executor.submit(self._execute, file_name).result()
这里你可以看到我已经为 循环拉出了的内部部分,在这里数据被加载、处理并存储到一个单独的函数中。这个函数我现在使用 loky executor 在一个专用的进程中运行这个函数,它确保了一旦完成就释放内存。这样,我的任务成功地处理了所有文件,我甚至能够进一步减少所需的内存量。最后,
包裹
在我的短文中,我谈到了 Python 应用程序中没有释放内存的问题。在像 AWS ECS 这样内存受限的环境中运行时,这个问题可能会很严重。通过将一个函数的执行放在一个专用的进程中,您可以确保在函数完成时释放内存等资源。希望,这对你以后有所帮助。
感谢您关注这篇文章。一如既往,如果有任何问题、意见或建议,请随时联系我或关注我,无论是在 Medium 还是通过 LinkedIn 。
如何使用 Python 和 AssemblyAI 调节音频数据
原文:https://towardsdatascience.com/how-to-moderate-audio-data-using-python-and-assemblyai-a5eab9910730
一个超越转录的特征
杰森·罗斯韦尔在 Unsplash 上的照片
在我之前的博客文章中,我浏览了 AssemblyAI API,涵盖了它的一些有趣特性,并展示了如何将其嵌入到 Streamlit 应用程序中,以便转录 Youtube 视频并自动检测其中的关键时刻(感兴趣吗?代码可在 Github 上获得。
如果你不熟悉 AssemblyAI,我鼓励你看看这篇文章。
但用几句话概括一下,AssemblyAI 是一个最先进的语音到文本 API,它不仅转录音频文件,还提供人工智能驱动的算法来理解转录本并从中获得洞察力。
在本帖中,我们将把音频内容调节作为这些人工智能支持的功能之一。**
我们会明白适度意味着什么,以及为什么它对互联网公司真的很重要。然后,我们将看到 AssemblyAI 如何从音频的角度解决这个问题:我们将检查代码,并一如既往地将其应用于特定的用例。
事不宜迟,让我们开始吧!🏊
内容适度—为什么很重要?
随着互联网不断增加用户生成的内容,如脸书帖子、Youtube 视频、抖音短片等,控制和调节这些数据的需求对于保护用户变得至关重要。
内容审核是每个平台都要处理的一项严肃任务,有时还会遇到困难:从检测 Youtube 视频中的色情内容,到检测 Twitter 上的仇恨言论,再到发现论坛中的脏话。
但内容审核可能更加微妙,因此可能适用于其他环境:确保视频在政治上中立,删除儿童节目中的酒精或赌博等敏感话题,监管教育平台的内容,评估客户和公司之间的互动,检测广告,显然还有更多。
如果你管理一个内容平台,无论是社交网络、儿童教育网站、企业论坛还是客户支持渠道,你都可能希望以某种形式使用内容审核。
如果您希望调节的数据是音频或视频格式,AssemblyAI 可以帮助您解决这个问题。
AssemblyAI 如何处理内容审核?
如果您想使用内容审核特性,您必须将 **content_safety**
参数添加到 POST 请求的头中,并将其值设置为**True**
。不要担心,我们将在下面的代码部分介绍这一点。
将此标志设置为**True**
将告诉 API 检查是否提到了以下一些话题。
作者截图
该列表实际上更长,甚至包括以下主题:
- 恐怖主义和武器
- 敏感的社会问题
- 亵渎
- NSFW 内容
当 AssemblyAI 在音频文件中发现其中一个主题时,它会赋予它一个置信度得分和严重性得分,以及原始文件中相应的时间戳。
这里有一个例子:
- 一个置信度得分是一个介于 0 和 1 之间的浮点数。它表示算法在检测给定对象时的置信度。可以解释为概率得分。高置信度表示该算法对其预测非常有把握。
- 严重性分数也是一个介于 0 和 1 之间的浮点数。反映出讨论的话题有多严肃和激烈。例如,自行车撞车和飓风都是事故,但前者远没有后者严重。
内容适度和严重性分数的实际使用案例
如果你关注美国和世界最近发生的事情,你可能已经注意到仇恨言论和仇恨犯罪充斥着新闻。
由于已经创建了许多 Youtube 内容来讨论这一全球性问题,我认为挑选一个视频示例并通过 AssemblyAI 来检查内容审核算法的行为会很有趣。
在这篇文章中,我决定分析下面这个视频,在这个视频中,青少年分享了他们在互联网上被仇恨言论和骚扰的经历。
AssemblyAI 可能会很容易地用仇恨言论标记这个视频。
但是它赋予每个标记部分的严重性分数是多少呢?它提供了一些见解吗?
这就是有趣的地方。让我们开始吧。
如果你想重现下面的步骤,你需要一个 AssemblyAI 账户。无需输入信用卡,您可以免费创建一个https://app.assemblyai.com/signup。
我将把这一节分成几个小部分,这样您就可以理解并轻松地重新运行代码。
👉从 Youtube 视频下载音频
我们首先从下载 Youtube 视频的音频文件开始。我们可以通过编程的方式做到这一点,所以没有必要去网上使用一些可疑的网站。
你可以通过安装 Pytube 包非常容易地做到这一点。
***pip install git+**[**https://github.com/baxterisme/pytube**](https://github.com/baxterisme/pytube)*
接下来你要做的就是导入Youtube
类,给它传递视频的 URL,提取音频流并通过提供输出文件夹调用下载方法。
如果您运行这个脚本,您将得到以下输出:
作者截图
👉上传音频文件到 AssemblyAI
在转录之前,AssemblyAI 需要通过 URL 访问音频文件。我们可以上传我们在 S3 的文件并提供一个链接,但是为了这个教程,我们将直接上传文件到 AssemblyAI 服务器。
为了能够上传一个音频文件到 AssemblyAI,我们需要使用 API 密匙。
但是首先,让我们把它从代码中隐藏起来,放在一个.env
文件中。
***API_KEY=<YOUR API KEY GOES HERE>***
然后我们将使用**python-dotenv**
包将其作为环境变量加载。
***pip install python-dotenv***
现在,要上传一个文件,推荐的方法是首先将它分成每个 5MB 的块,并将这些块放入一个生成器中,我们将这些块作为数据负载传递给查询:这就是下面的脚本所做的。
**read_file**
函数负责分割文件,**upload**
函数负责发送 POST 请求。
如果您运行此代码,您将获得上传 URL。
作者截图
👉提交转录作业
一旦获得上传 URL,就可以用它向 AssemblyAI 提交转录作业。
激活内容审核发生在这一步。
为此,您必须将**content_safety**
参数设置为**True**
,并将其作为 JSON 有效负载传递给查询。
提交作业后,它将通过一个队列,您将获得一个重新传输 id。
您不会立即得到结果,因为转录是一个 异步任务。
作者截图
👉获取转录
一旦转录完成(您可以随时从界面检查处理队列),您可以使用转录 id 并获取结果。
这是一个稍微不同的端点上的简单 GET 请求。
如果您运行这段代码,您将获得以下 JSON 输出——您可以查看 AssemblyAI 文档来了解这些字段。
这是输出文本。你可以自己查一下:转录质量惊人。
现在,如果你仔细观察,你会注意到一个**content_safety_labels**
键,它包括视频中被标记为hate_speech
的不同部分。
每个部分都由相应的文本、分类标签以及置信度和严重性分数来表示。
👉解释严重性分数
我并不惊讶 AssemblyAI 在整个文本中发现了仇恨言论。这显然是视频的中心话题。
然而,我发现有趣的是严重性分数。让我们来看看。
下面是音频中被标记为高严重性分数的部分:
这是另一个被标记为低严重性分数的问题。
在两个片段中,置信度得分都很高。
但是,由于讨论主题的方式不同,严重性分数也不同。
- 第一部分(高度严重)分享了一些青少年在网上面临反犹太主义和仇恨言论时的痛苦和苦难的戏剧性个人经历。
- 第二部分(低严重性)更加中性。发言的少年给出了他所看到的仇恨言论的正式定义。
严重性分数是一个有趣的指标,您可以使用它来确定您希望分析和管理的部分的优先级。它帮助你放大关键的部分,丢弃那些更中性的部分。
如果你想玩代码,可以在 Github 上找到。
参考资料:
感谢阅读🙏
如果您已经做到这一步,我想感谢您的时间,并希望我已经阐明了 AssemblyAI 的内容审核特性。
您可以在不同的上下文中使用内容审核来管理数据,也可以通过将它用作主题建模工具来重新调整它的用途。
今天就这些了。下次见!👋
新到中?您可以每月订阅 5 美元,并解锁各种主题的无限文章(技术、设计、创业……)。您可以通过点击我的推荐链接来支持我
*https://ahmedbesbes.medium.com/membership
由 Unsplash 上的 Karsten Winegeart 拍摄*
如何大规模监控数据湖的健康状况
原文:https://towardsdatascience.com/how-to-monitor-data-lake-health-status-at-scale-d0eb058c85aa
配套的 GitHub 库:【Spark 手把手的远大前程
带着巨大的期望和火花构建数据质量工作流
介绍
在 Mediaset ,数据湖是每个想要获得一些公司见解或激活数据的人日常使用的基本工具。
根据定义,数据湖是"一个集中的存储库,可以存储任何规模的所有结构化和非结构化数据。您可以本地存储来自源的数据,而不必在运行时转换它们。这允许您保留大量的原始数据,您可以在以后使用不同类型的分析来激活这些数据。
访问数据湖的 Mediaset 员工数量正在上升,随着数据湖的增长,我们接收和保存的产品和数据的数量也在增加。随着用户和归档数据量的增加,管理数据湖的复杂性也在增加。
这是一个关键点,事实上,如果没有实现数据质量和数据治理系统,数据湖可能会变成一个数据沼泽:一个没有组织和精确元数据的数据存储,以使检索变得容易 " ( Integrate.io )。
数据沼泽可能会很快出现,并给希望实施高级分析解决方案的数据驱动型公司带来问题。如果对数据进行严密管理,并执行持续的数据健康状态检查,Data Lake 有可能为公司提供一个准确的、改变游戏规则的业务洞察工具。
全面控制数据湖中的持久数据,并知道会从数据湖中得到什么,以防止它变成数据沼泽,变得越来越重要和相关。
为此,我们实施了数据质量工作流,以支持不同的业务部门完成数据验证的高要求任务,跟踪数据运行状况、漂移和异常情况。这有助于人们不断评估摄取的和转换的数据,增强数据的可靠性和数据驱动产品的总体质量。
该工作流是围绕开源框架 [Great Expectations](http://helps data teams eliminate pipeline debt, through data testing, documentation) (GE)构建的,该框架将自己定义为“一个共享的、开放的数据质量标准,帮助数据团队始终知道对新数据有什么期望。“GE 是一个 python 包,它使我们能够编写测试并评估数据质量。它的简单性和可定制性允许我们轻松地将其与 ETL 管道集成,以验证我们从输入和输出数据中期望的得到满足。
在本文中,我们介绍了 Mediaset 的数据质量工作流的体系结构。我们列出了促使我们构建它的关键点以及整个涉及的技术堆栈。
Mediaset 的数据湖:一个实际的用例
Mediaset 是意大利和西班牙领先的私营电视出版商,是真正的观众领导者,拥有五个公共网络和 30 多个免费和付费主题频道。
每天,数百万人观看视频点播和直播,阅读文章,收听 Mediaset 服务提供的广播节目。人们通过不同的设备与媒体集属性进行交互:智能手机、网络浏览器、智能电视和互联网电视。所有这些视频浏览量、页面浏览量和点击量都来自 Mediaset 系统,以了解我们的客户(那些接受简介的客户)喜欢看、读和听什么,并提高产品的总体质量。
在过去几年中,Mediaset 决定投入资源设计和构建一个数据湖,以存储用户通过公司提供的几个平台和服务与其设备进行交互时产生的所有数据。
为了勾勒出 Mediaset 工作的总体环境和数量级,我们提供了由*Mediaset Business Digital(MBD)*提供的摘要信息,该业务部门负责客户开发、数据接收和第一层数据转换的提供:
- 媒体集数据湖每天存储约 100 千兆字节的客户端生成的原生数据及其与媒体集属性和平台(流媒体平台、新闻网站、博客和电台)的交互;
- 获取几种类型的数据:点击流、页面浏览量、视频浏览量、视频播放器互动、营销活动结果、服务台票证、社交媒体反馈等等;
- 数据湖存储从客户端获取的原始数据和 ETL 管道的输出,由业务和数据分析师用于数据探索任务,由数据科学家用于机器学习模型训练;
- 从第一天起,当一个新的平台、服务或资产出现时,数据就存储在数据湖中,以后当业务需求精确时再激活它们。
大数据,大责任
随着数据湖的发展,存储数据量的增加,以及每天查询和激活数据的人数的增加,控制数据湖健康状态的必要性开始出现。
更具体地说,遇到的临界点有四个:
- 验证已发布的客户端(移动应用程序、智能电视应用程序和网站)正在正确跟踪所有事件(点击、查看和操作),因此存储在数据湖中的所有数据都是正确和可信的。否则,必须将任何发现的问题通知开发团队,以便尽快解决。
- 扩展 ETL 管道单元测试,检查实现的转换是否返回您期望的输出。
- 监控所有管道或所有服务是否启动并运行,跟踪每天的数据量变化。
- 检测机器学习模型中涉及的数据集中的数据漂移或数据退化,防止错误预测或误导性预测。
这些要点促使 Mediaset 业务数字部门开发了一个能够监控数据湖健康状态的数据质量工作流程。
这个过程中涉及的主要工具是 Great Expectations (GE),它提供了采用 Spark 作为执行引擎的可能性,非常适合当前的 Mediaset 数据堆栈。GE 也是一个开源项目,拥有巨大的社区支持,被设计成可扩展和完全可定制的。
数据质量工作流概述
注意:这不是一个“远大前程简介”教程,而是我们实现的监控数据湖健康状态的架构的概述,以及我们如何使用 GE 来完成这项任务。
该工作流已经开发并与基于 Amazon Web Services (AWS)的当前媒体集数据堆栈集成。涉及的主要服务有:
- 亚马逊 S3:“一种对象存储服务,提供业界领先的可扩展性、数据可用性、安全性和性能”(AWS))。这是中央数据湖存储器,所有接收和转换的数据都存储在这里。
- ***AWS Glue Data Catalog:“***提供了跨多种数据源和数据格式的统一元数据库。它提供了与亚马逊 S3、亚马逊雅典娜和亚马逊 EMR 的开箱即用集成”( AWS )。
- ***亚马逊 EMR:“***一个托管集群平台,简化在 AWS 上运行大数据框架,如 Apache Spark,以处理和分析海量数据”( AWS )。Amazon EMR 代表了 MBD 单元所采用的 ETL 工作的领先 AWS 服务;这与作为数据协调器的 Airflow 相结合,使我们能够开发和安排日常转换例程。
- 亚马逊 Athena: “一种交互式查询服务,可以使用标准 SQL 轻松分析存储在亚马逊 S3 的数据”( AWS )。
数据质量工作流架构(图片由作者提供)
实施的数据质量工作流程(参见上述架构)包括五个步骤。
1。数据质量套件开发
一切都从这里开始,从本地开发环境开始,这允许你开发 GE 称之为 的期望套件 ,一组规则(期望)描述你对数据集的期望。该环境由一个 Docker 映像组成,该映像运行一个带有 PySpark 的 Jupyter notebook 实例和您需要的所有 python 包。一旦您获得了想要评估的数据子集(原始数据或经过处理的数据),您就可以在笔记本上编写数据必须满足的所有期望,并以 JSON 文件的形式生成期望套件。
基于 docker 的开发环境也在定制期望开发期间支持你;您可以使用 Docker 映像作为远程 python 解释器,在您最喜欢的 IDE 中对所有期望进行编码和测试。
开发定制期望的可能性代表了 GE 为我们的工作流程提供的最重要的特征之一。这些类型的期望确实允许我们测试甚至是最复杂的多列条件,给予细致的数据验证。
奖金:检查仓库中三个定制期望类型的代码:单列、对列和多列。它还包括单元测试以及使用 PyCharm 使用所提供的 Docker 映像运行它们的步骤。
2。套件部署
一旦套件准备就绪(文档化和测试),提交到 git 存储库的主分支将触发一个持续集成管道,该管道将编译好的期望套件和所有定制的期望 python 模块复制到一个 S3 桶中。CI 管道还负责生成最新的 GE 数据文档,并将其存储在专用的 S3 存储桶中。
3。数据验证运行
是时候真正评估这些数据有多好了。如上所述,我们采用 Airflow 作为数据编排器,其中我们实现了几个数据质量 Dag。详细来说,对于原始数据,我们有专门运行验证作业的专用 DAG(这种 DAG 涉及的Operators
和Sensors
的顺序见下图);
验证原始数据质量的气流 DAG 结构(图片由作者提供)
在处理数据时,我们将验证气流任务附加到转换任务(见下图)以使整个处理层保持一致:如果转换生成质量较差的数据,我们会收到警报,以便我们可以中断所有后续任务(见步骤 4)。
验证处理数据质量的气流 DAG 结构(图片由作者提供)
验证作业获取先前开发和部署的期望套件和定制期望作为输入。数据验证输出是一个 JSON 文件,在 S3 上以原始格式存储后,通过气流PythonOperator
进行解析,并作为分区的拼花文件保存在数据湖中。最后,AWS Glue 数据目录中的元数据用新的分区进行了更新,使得数据质量验证结果可以用 Amazon Athena 进行查询。
额外收获:在配套的资源库中,你可以找到一个现成的“验证你的数据”作业,你可以快速运行它来模拟我们在这一步用 Amazon EMR 实现的东西(即 Docker 容器运行一个
spark-submit
命令来执行数据验证 python 模块)。
4。数据验证结果分析
我们决定将 Apache 超集集成到数据质量工作流中,以探索验证结果,并使其可视化尽可能有影响力。Superset 是一个开源的数据探索和可视化平台,能够连接到现代数据库(包括 Amazon Athena),易于掌握,内置丰富的可视化情节。由于其简单性,超集使我们能够专注于核心任务,例如设计定制指标和通过交互式仪表板可视化见解来评估我们的数据质量,而不是工具本身(参见下面的截图以获得样本超集数据质量仪表板)。
用于评估数据的指标示例如下:
- 数据量
- 不成功的期望百分比
- 至少有一个不成功预期的所有列的列表
- 每列的错误记录的百分比
- 第一个 n 预期不成功的每列的意外值。
超集最后提供了两个对工作流有用的关键特性:
- 警报 在达到 SQL 条件时被触发,发送一个关于 Slack 的通知或电子邮件。您可以为您想要监控的 KPI 设置阈值(,例如,“今天和昨天运行之间的不成功预期数的变化必须低于 10%”,,当条件不满足时,将发送通知警报。
- 报告 按计划发送,允许您分析与上周相关的验证结果,以更有条理、更清晰的方式传达结果。
“超集数据质量仪表板”的示例—仪表板由以下部分组成:a) 左上角的数据量直方图,按媒体集属性分组;b)在右上角的环形图上,显示每个媒体集属性的不成功预期数;c)对于每个数据集列,列出不成功的期望、用于评估被检查列的补充列(在多列期望的情况下)以及有问题的属性的数量的表格;d)折线图,按属性分组,显示所选列的每日(上个月)不成功记录的百分比-期望值。(图片由作者提供)
5。数据文件
该工作流程的最后一步是发布数据文档网站,该网站之前由 Great Expectations 通过 CI pipeline 触发器生成。Data Docs 包含属于每一列的所有期望的完整列表,以及由表和套件组织的已实现规则的描述。除了为每个期望套件提供文档外,【Great Expectations Data Docs 还允许我们与非技术人员分享为每个表开发的检查,从而更容易讨论可能的和未来的套件增强。
结论
在本文中,我们向您展示了基于 Great Expectations 实现的工作流,它赋予 Mediaset 持续监控数据湖健康状态的能力。这防止了数据湖变成数据沼泽,保持了数据的高可靠性,提高了所有涉及数据的项目的质量。
一旦部署了数据质量工作流程,不同 Mediaset 业务部门的开发人员只需专注于 Expectation Suites 开发和(显然是)数据质量警报和报告分析。
本地开发环境为所有业务单元提供了一个舒适的地方来开发它们的套件,因此,在监视它们权限内的数据时是独立的。每个业务单位都能够拒绝自己的需求,并通过本地和定制的期望使它们达到更高的期望。
开发环境结合了云的能力和弹性,以及 EMR 等服务,允许在任何规模上应用期望,包括原始数据和处理后的数据,主动监控我们每天摄取并保存在我们心爱的数据湖中的内容。在这种情况下,EMR 集群的成本将取决于您想要评估的数据集的大小、套件中包含的预期数量以及已经实现的自定义预期的复杂性。
套件中所有控件的组织-每表,以及数据文档的自动生成,为所有用户提供了一种简单的方式来检查期望套件所覆盖的表的列表,并查阅为每一列实现的逻辑。
最后,可视化工具允许数据验证结果分析民主化,使得那些希望在使用数据之前对表或数据湖进行状态检查的非技术人员也可以访问这些结果。
感谢您阅读我们的作品!
如果您有问题或反馈,请随时给我发送连接。
承认
感谢来自 Mediaset 的 Nicola 、 Daniele 、 Fabio 、来自 Coveo 的 Jacopo 和来自 Tecton 的 Danny 对本文和 Github 资源库的评论和建议。
参考
- 什么是数据湖?—亚马逊网络服务(AWS)。https://AWS . Amazon . com/big-data/data lakes-and-analytics/what-a-data-lake/
- 把你的数据湖变成数据沼泽| integrate . io .https://www . integrate . io/blog/turning-Your-Data-Lake-Into-a-Data-Swamp/
- 什么是亚马逊 S3?—亚马逊网络服务(AWS)。
https://docs . AWS . Amazon . com/Amazon S3/latest/user guide/welcome . html - 升级到 AWS Glue 数据目录— Amazon Athena。https://docs.aws.amazon.com/athena/latest/ug/glue-faq.html
- 什么是亚马逊 EMR?—亚马逊网络服务(AWS)。
https://docs . AWS . Amazon . com/EMR/latest/management guide/EMR-what-is-EMR . html - 亚马逊雅典娜是什么?—亚马逊网络服务(AWS)。
https://docs.aws.amazon.com/athena/latest/ug/what-is.html