原文:
annas-archive.org/md5/5532fd447031f1db26ab91548948a023
译者:飞龙
前言
在今天这个快节奏的数据驱动的世界里,人们容易被人工智能(AI)突破性进展和先进的机器学习(ML)模型所吸引。但问问任何经验丰富的数据科学家或工程师,他们都会告诉你同样的事情:任何成功数据项目的真正基础不是炫目的算法或复杂的模型——而是数据本身, 更重要的是,如何准备这些数据。
在我的职业生涯中,我学到数据预处理是数据科学中的默默无闻的英雄。它是一个细致且常常复杂的过程,将原始数据转化为可靠的资产,准备好进行分析、建模,最终用于决策。我亲眼见证了正确的预处理技术如何改变一个组织对数据的处理方式,将潜在的挑战转化为强大的机会。
然而,尽管数据预处理如此重要,它常常被忽视或低估。许多人将其视为一个繁琐的步骤,一个拖慢构建模型和提供洞察力的瓶颈。但我一直认为,这个阶段才是最关键的工作阶段。毕竟,即便是最复杂的算法也无法弥补数据质量差的不足。这就是为什么我将自己大部分的职业生涯都奉献给了掌握这一艺术——探索最佳的工具、技术和策略,使得预处理更加高效、可扩展,并且与不断发展的 AI 领域保持一致。
本书旨在揭开数据预处理过程的神秘面纱,既提供传统方法的扎实基础,也展望了新兴技术的前景。我们将探讨如何利用 Python 更有效地清理、转换和组织数据。我们还将关注大语言模型(LLMs)的出现,如何重新定义这个领域的可能性。这些模型已经证明是改变游戏规则的工具,自动化了曾经需要手工完成且耗时的任务,并提供了提升数据质量和可用性的新方法。
在本书的过程中,我将分享我的经验、遇到的挑战和一路上学到的教训。我希望不仅能为你提供一个技术性的路线图,还能让你更深入理解数据预处理在当今数据生态系统中的战略重要性。我坚信“通过实践学习”的理念,因此本书包含了大量的代码示例,供你跟随学习。我鼓励你尝试这些示例,实验代码,并挑战自己将这些技术应用到你自己的数据集中。
在本书的结尾,你将具备足够的知识和技能,不仅将数据预处理视为一个必要步骤,而是将其视为你整体数据策略中的一个关键组成部分。
所以,无论你是数据科学家、工程师、分析师,还是仅仅希望提升数据处理理解的人,我邀请你与我一起踏上这段旅程。我们将共同探索如何利用数据预处理的力量,释放数据的全部潜力。
本书适用对象
本书适合具有 Python 基础知识、较好掌握统计概念,并有一定数据操作经验的读者。本书不会从零开始,而是建立在现有技能的基础上,向你介绍复杂的预处理策略、实践代码示例和实际练习,要求读者对数据科学和分析的核心原理有一定的熟悉程度。
本书内容
第一章,数据摄取技术,提供了关于数据摄取过程的全面概述,强调了它在从各种来源收集和导入数据到存储系统进行分析中的作用。你将探索不同的摄取方法,如批量模式和流模式,比较实时和半实时数据摄取,并了解数据源背后的技术。本章突出了这些方法的优缺点及其实际应用。
第二章,数据质量的重要性,强调了数据质量在商业决策中的关键作用。它突出了使用不准确、不一致或过时数据的风险,这可能导致错误的决策、损害声誉和错失机会。你将了解为什么数据质量至关重要,如何在不同维度上衡量数据质量,以及数据孤岛对维持数据质量的影响。
第三章,数据剖析——理解数据结构、质量和分布,探索了数据剖析,重点审视和验证数据集,以理解其结构、模式和质量。你将学习如何使用工具如 pandas Profiler 和 Great Expectations 进行数据剖析,并了解何时使用每个工具。此外,本章还涉及了处理大量数据的方法,并比较了不同的剖析方法,以提高数据验证的效果。
第四章,清理混乱的数据和数据操作,重点介绍了清理和操作数据的关键策略,帮助实现高效准确的分析。内容包括重命名列、删除无关或冗余数据、修正不一致的数据类型和处理日期时间格式等技术。掌握这些方法后,你将学会如何提升数据集的质量和可靠性。
第五章,数据转换 – 合并与连接,探索了通过合并、连接和拼接数据集来转换和操作数据的技术。它涵盖了从多个来源合并数据集、有效处理重复数据并提高合并性能的方法。本章还提供了一些实用技巧,以简化合并过程,确保数据高效集成,便于洞察分析。
第六章,数据分组、聚合、过滤与应用函数,涵盖了数据分组和聚合的基本技术,这对于总结大数据集并生成有意义的洞察至关重要。本章讨论了通过聚合值、减少数据量和提高处理效率来处理缺失或噪声数据的方法。它还重点讲解了如何通过不同的键对数据进行分组、应用聚合和自定义函数,以及过滤数据,以创建有价值的特征,供深入分析或机器学习使用。
第七章,数据接收端,聚焦于数据处理中的关键决策,特别是选择适合存储和处理需求的数据接收端。它深入探讨了四个基本要素:选择合适的数据接收端、选择正确的文件类型、优化分区策略,以及理解如何设计一个可扩展的在线零售数据平台。本章为你提供了提高数据处理管道效率、可扩展性和性能的工具。
第八章,检测与处理缺失值与异常值,深入探讨了识别和处理缺失值及异常值的技术。它介绍了从统计方法到先进的机器学习模型的多种方法,以有效解决这些问题。本章的重点领域包括检测和处理缺失数据、识别单变量和多变量异常值,以及管理各种数据集中的异常值。
第九章,归一化与标准化,涵盖了诸如特征缩放、归一化和标准化等关键预处理技术,这些技术确保机器学习模型能够有效地从数据中学习。你将探索包括将特征缩放到某个范围、Z-score 缩放和使用鲁棒缩放器等不同技术,以应对机器学习任务中的各种数据挑战。
第十章,处理类别特征,讲解了管理类别特征的重要性,类别特征代表数据集中的非数值信息。你将学习多种编码技术,包括标签编码、一热编码、目标编码、频率编码和二进制编码,以将类别数据转化为机器学习模型可以使用的格式。
第十一章,时间序列数据分析,深入探讨了时间序列分析的基础知识,涵盖了各行业中的关键概念、方法论和应用。内容包括理解时间序列数据的组成部分和类型,识别和处理缺失值,以及分析趋势和模式的技术。本章还讲解了如何处理异常值和特征工程,以提高时间序列数据预测建模的效果。
第十二章,LLM 时代的文本预处理,重点介绍了掌握文本预处理技术,这些技术对于优化 LLMs(大语言模型)的性能至关重要。它涵盖了清洗文本、处理稀有词汇和拼写变化、分块以及分词策略的方法。此外,它还讨论了将词元转换为嵌入向量的过程,强调了调整预处理方法以最大化 LLMs 潜力的重要性。
第十三章,使用 LLMs 进行图像和音频预处理,探讨了针对非结构化数据,特别是图像和音频的预处理技术,以提取有意义的信息。它包括图像预处理方法,如 光学字符识别(OCR)和使用 BLIP 模型生成图像描述。本章还探讨了音频数据处理,包括使用 Whisper 模型将音频转换为文本,全面介绍了在 LLMs 背景下处理多媒体数据的相关内容。
为了最大限度地发挥本书的效用
为了充分利用本书的内容,你应该具备良好的 Python 基础,并掌握数据工程和数据科学的基本知识。
本书涉及的软件/硬件 | 操作系统要求 |
---|---|
Python 3 | Windows、macOS 或 Linux |
Visual Studio Code(或你首选的 IDE) |
如果你使用的是本书的电子版,我们建议你自己输入代码,或者通过书中的 GitHub 仓库访问代码(链接会在下一个章节提供)。这样可以避免复制和粘贴代码时可能出现的错误。
GitHub 仓库遵循本书的章节结构,所有脚本按照每个章节中的部分进行编号。每个脚本是独立的,因此你可以无需事先运行所有脚本就继续往前进行。然而,强烈建议按照书中的流程进行操作,以确保你不会遗漏任何必要的信息。
下载示例代码文件
你可以从 GitHub 上下载本书的示例代码文件,链接为 github.com/PacktPublishing/Python-Data-Cleaning-and-Preparation-Best-Practices
。如果代码有更新,GitHub 仓库会同步更新。
我们的丰富图书和视频目录中还有其他代码包,您可以访问github.com/PacktPublishing/
查看。
使用的约定
本书中使用了多种文本约定。
文本中的代码
:表示文本中的代码字、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名。示例:“delete_entry() 函数用于删除条目,展示了如何从存储中删除数据”
代码块设置如下:
def process_in_batches(data, batch_size):
for i in range(0, len(data), batch_size):
yield data[i:i + batch_size]
当我们希望您注意代码块中的某个特定部分时,相关的行或项目会使用粗体显示:
user_satisfaction_scores = [random.randint(1, 5) for _ in range(num_users)]
任何命令行输入或输出如下所示:
$ mkdir data
pip install pandas
粗体:表示新术语、重要单词或您在屏幕上看到的词。例如,菜单或对话框中的单词以粗体显示。示例:“它涉及将数据存储在远程服务器上,可以通过互联网从任何地方访问,而不是在 本地设备上”
提示或重要注意事项
如此显示。
保持联系
我们始终欢迎读者的反馈。
一般反馈:如果您对本书的任何方面有疑问,请通过电子邮件联系我们:customercare@packtpub.com,并在邮件主题中注明书名。
勘误:尽管我们已尽力确保内容的准确性,但错误仍然会发生。如果您在本书中发现错误,我们将非常感激您向我们报告。请访问www.packtpub.com/support/errata并填写表单。
盗版:如果您在互联网上发现我们的作品的非法复制版本,我们将非常感激您提供该位置地址或网站名称。请通过版权@packt.com 与我们联系,并附上该材料的链接。
如果您有兴趣成为作者:如果您在某个领域有专业知识,并且有兴趣写书或为书籍做贡献,请访问authors.packtpub.com。
分享您的想法
一旦您阅读完《Python 数据清理与准备最佳实践》,我们很想听听您的想法!请点击此处直接进入 Amazon 书评页面并分享您的反馈。
您的书评对我们和技术社区都非常重要,将帮助我们确保提供优质内容。
下载本书的免费 PDF 版本
感谢您购买本书!
您是否喜欢在旅途中阅读,但又无法随身携带纸质书籍?
你的电子书购买是否与所选设备不兼容?
别担心,现在每本 Packt 书籍都会附带该书的 DRM-free PDF 版本,免费提供。
在任何地方、任何设备上阅读。搜索、复制并粘贴你最喜欢的技术书籍中的代码,直接应用到你的应用程序中。
优惠不仅仅如此,你还可以获得独家折扣、时事通讯和每天发送到你邮箱的精彩免费内容
按照这些简单的步骤即可享受福利:
- 扫描二维码或访问下面的链接
packt.link/free-ebook/9781837634743
-
提交你的购买证明
-
就是这样!我们会直接将免费的 PDF 和其他福利发送到你的邮箱
第一部分:上游数据摄取与清理
本部分聚焦于数据处理的基础阶段,从数据摄取开始,确保数据的质量和结构,以便于后续任务的处理。它指导读者完成导入、清理和转换数据的关键步骤,为有效的数据分析奠定基础。章节内容涵盖了多种数据摄取方法、如何保持高质量的数据集、如何进行数据剖析以获得更好的见解,并且如何清理杂乱数据以使其准备好进行分析。此外,还涉及了如合并、连接、分组和过滤数据等高级技术,同时介绍了如何选择合适的数据接收端或存储地,以优化处理管道。本部分的每个章节都为读者提供了处理原始数据、将其转化为干净、结构化且可用形式的知识。
本部分包含以下章节:
-
第一章*,数据摄取技术*
-
第二章*,数据质量的重要性*
-
第三章*,数据剖析* – 理解数据结构、质量和分布
-
第四章*,清理杂乱数据与数据操作*
-
第五章*,数据转换* – 合并与连接
-
第六章*,数据分组、聚合、过滤与应用函数*
-
第七章*,数据接收端*
第一章:数据摄取技术
数据摄取是数据生命周期的一个关键组成部分,它为随后的数据转换和清理奠定了基础。它涉及从各种来源收集和导入数据到存储系统的过程,数据可以在此系统中访问和分析。有效的数据摄取对于确保数据的质量、完整性和可用性至关重要,这直接影响数据转换和清理过程的效率和准确性。在本章中,我们将深入探讨不同类型的数据源,探索各种数据摄取方法,并讨论它们各自的优缺点以及实际应用。
本章将涵盖以下主题:
-
批量模式的数据摄取
-
流式模式的数据摄取
-
实时摄取与半实时摄取
-
数据源技术
技术要求
你可以在以下 GitHub 仓库中找到本章的所有代码:
github.com/PacktPublishing/Python-Data-Cleaning-and-Preparation-Best-Practices/tree/main/chapter01
你可以使用你喜欢的 IDE(VS Code、PyCharm、Google Colab 等)来编写和执行代码。
批量模式的数据摄取
批量摄取是一种数据处理技术,其中大量数据在预定的时间间隔内收集、处理并加载到系统中,而不是实时进行。通过将数据分成批次处理,组织可以高效地处理大量数据。例如,一家公司可能会在一天内收集客户交易数据,然后在非高峰时段将其作为一个批次处理。这种方法对于需要处理大量数据但不要求即时分析的组织特别有用。
批量摄取有益于优化系统资源,通过将处理负载分配到计划好的时间,通常是在系统空闲时进行。这减少了计算资源的压力,并且可以降低成本,尤其是在基于云的环境中,计算能力是按使用量计费的。此外,批处理简化了数据管理,因为它允许对大规模数据集应用一致的转换和验证。对于数据流规律可预测的组织,批量摄取提供了一种可靠、可扩展且具有成本效益的数据处理和分析解决方案。
让我们更详细地探讨批量摄取,从其优点和缺点开始。
优势与劣势
批量摄取提供了几个显著的优势,使其成为许多数据处理需求的有吸引力的选择:
-
效率是一个关键优势,因为批处理允许在一次操作中处理大量数据,优化了资源使用并最小化了开销。
-
成本效益是另一个好处,减少了对连续处理资源的需求,降低了运营成本。
-
简单性使得相对于实时摄取,更容易管理和实现周期性数据处理任务,后者通常需要更复杂的基础设施和管理。
-
鲁棒性,因为批处理非常适合进行复杂的数据转换和全面的数据验证,确保高质量、可靠的数据。
然而,批处理摄取也带来一些缺点:
-
数据生成和可用性之间存在固有的延迟,对于需要实时洞察力的应用程序来说,这可能是一个关键问题。
-
批处理窗口期间可能会出现资源峰值,导致高资源使用率和潜在的性能瓶颈。
-
可伸缩性也可能是一个问题,处理非常大的数据集可能需要大量的基础设施投资和管理。
-
最后,维护是批处理摄取的一个关键方面;它需要仔细的调度和持续的维护,以确保批处理作业的及时可靠执行。
让我们来看看批处理模式中数据摄取的一些常见用例。
批处理摄取的常见用例
任何数据分析平台,如数据仓库或数据湖,都需要定期更新的数据用于商业智能(BI)和报告。批处理摄取至关重要,因为它确保数据始终使用最新信息进行更新,使企业能够进行全面和最新的分析。通过批处理处理数据,组织可以高效处理大量的交易和运营数据,将其转换为适合查询和报告的结构化格式。这支持 BI 倡议,允许分析师和决策者生成深刻见解的报告,跟踪关键绩效指标(KPIs),并做出数据驱动的决策。
提取、转换和加载(ETL)过程是数据集成项目的基石,批量摄取在这些工作流程中起着关键作用。在 ETL 过程中,数据从各种来源提取,经过转换以适应目标系统的操作需求,然后加载到数据库或数据仓库中。批处理允许有效处理这些步骤,特别是在处理需要大量转换和清洗的大型数据集时。这种方法非常适合周期性数据整合,将来自不同系统的数据集成为统一视图,支持数据迁移、系统集成和主数据管理等活动。
批量数据导入在备份和归档中也得到了广泛应用,这些过程对于数据的保存和灾难恢复至关重要。定期的批处理允许按计划备份数据库,确保所有数据都能在定期间隔内被捕获并安全存储。这种方法最大限度地减少了数据丢失的风险,并在系统故障或数据损坏时提供可靠的恢复点。此外,批处理还用于数据归档,将历史数据定期从活动系统转移到长期存储解决方案中。这不仅有助于管理存储成本,还能确保重要数据被保留并可供合规、审计或历史分析使用。
批量数据导入的使用案例
批量数据导入是一个系统化的过程,涉及多个关键步骤:数据提取、数据转换、数据加载、调度和自动化。为了说明这些步骤,让我们以一个投资银行为例,探讨它如何处理和分析交易数据以确保合规性和生成绩效报告。
投资银行的批量数据导入
投资银行需要从多个金融市场收集、转换并加载交易数据到一个中央数据仓库。这些数据将用于生成每日合规报告、评估交易策略以及做出明智的投资决策。
数据提取
第一步是识别数据提取的来源。对于投资银行来说,这包括交易系统、市场数据提供商和内部风险管理系统。这些来源包含关键数据,如交易执行细节、市场价格和风险评估。一旦确定了来源,数据就会通过连接器或脚本进行收集。这涉及建立数据管道,从交易系统提取数据,导入实时市场数据流,并从内部系统提取风险指标。提取的数据将暂时存储在暂存区,待处理。
数据转换
提取的数据通常包含不一致、重复和缺失值。数据清洗会移除重复项、填补缺失信息并纠正错误。对于投资银行来说,这确保了交易记录的准确性和完整性,为合规报告和绩效分析提供了可靠的基础。清洗后,数据会进行如聚合、连接和计算等转换。例如,投资银行可能会聚合交易数据以计算每日交易量,连接交易记录与市场数据以分析价格波动,并计算关键指标如盈亏(P&L)和风险暴露。转换后的数据必须映射到目标系统的模式中。这涉及将数据字段与数据仓库的结构对齐。例如,交易数据可能会映射到代表交易、市场数据和风险指标的表中,确保与现有数据模型的无缝集成。
数据加载
转换后的数据以批处理方式进行处理,这使得投资银行能够高效地处理大量数据,在一次运行中执行复杂的转换和聚合。一旦处理完成,数据会被加载到目标存储系统中,如数据仓库或数据湖。对于投资银行来说,这意味着将清洗和转换后的交易数据加载到他们的数据仓库中,从而可以用于合规报告和绩效分析。
调度与自动化
为了确保批量摄取过程顺利且一致地运行,通常会使用调度工具,如 Apache Airflow 或 Cron 作业。这些工具自动化数据摄取工作流,并安排在固定的时间间隔运行,例如每晚或每天一次。这使得投资银行能够在没有人工干预的情况下获得最新的数据以供分析。实施监控至关重要,用于跟踪批处理作业的成功与性能。监控工具提供作业执行的洞察,帮助识别任何失败或性能瓶颈。对于投资银行来说,这确保了数据摄取过程中出现的任何问题都能及时被发现并解决,从而维护数据管道的完整性和可靠性。
带示例的批量摄取
让我们来看一个用 Python 编写的简单批处理摄取系统示例。这个示例将模拟 ETL 过程。我们将生成一些模拟数据,按批处理方式处理它,并将其加载到模拟数据库中。
你可以在 GitHub 仓库的github.com/PacktPublishing/Python-Data-Cleaning-and-Preparation-Best-Practices/blob/main/chapter01/1.batch.py
中找到这部分代码。要运行这个示例,我们不需要安装任何特别的库,只需要确保在标准的 Python 环境(Python 3.x)中运行即可。
-
我们创建一个
generate_mock_data
函数,用于生成模拟数据记录的列表:def generate_mock_data(num_records): data = [] for _ in range(num_records): record = { 'id': random.randint(1, 1000), 'value': random.random() * 100 } data.append(record) return data A list of dictionaries is returned, each representing a data record.
-
接下来,我们创建一个批处理函数:
def process_in_batches(data, batch_size): for i in range(0, len(data), batch_size): yield data[i:i + batch_size]
该函数将数据(数据记录的列表)和
batch_size
(每个批次的记录数)作为参数。该函数使用for
循环以batch_size
为步长遍历数据。使用yield
关键字生成每个大小为batch_size
的数据批次,返回一个生成器来产生数据批次。 -
我们创建一个
transform_data
函数,用于转换批次中的每一条记录:def transform_data(batch): transformed_batch = [] for record in batch: transformed_record = { 'id': record['id'], 'value': record['value'], 'transformed_value': record['value'] * 1.1 } transformed_batch.append(transformed_record) return transformed_batch
该函数的参数是批次,它是一个需要转换的数据记录列表。转换逻辑很简单:每个记录中添加一个新的
transformed_value
字段,它是原始值乘以 1.1。最后,我们得到了一个转换后的记录列表。让我们看看一些转换后的记录:{'id': 558, 'value': 12.15160339587219, 'transformed_value': 13.36676373545941} {'id': 449, 'value': 99.79699336555473, 'transformed_value': 109.77669270211021} {'id': 991, 'value': 79.65999078145887, 'transformed_value': 87.62598985960477}
-
接下来,我们创建一个
load_data
函数来加载数据。这个函数模拟将每个转换后的记录加载到数据库中的过程:def load_data(batch): for record in batch: # Simulate loading data into a database print(f"Loading record into database: {record}")
该函数以批次作为参数,批次是一个准备加载的转换后的数据记录列表。每条记录都会打印到控制台,以模拟将其加载到数据库中。
-
最后,我们创建一个
main
函数。这个函数调用了所有前面提到的函数:def main(): # Parameters num_records = 100 # Total number of records to generate batch_size = 10 # Number of records per batch # Generate data data = generate_mock_data(num_records) # Process and load data in batches for batch in process_in_batches(data, batch_size): transformed_batch = transform_data(batch) print("Batch before loading:") for record in transformed_batch: print(record) load_data(transformed_batch) time.sleep(1) # Simulate time delay between batches
这个函数调用
generate_mock_data
来生成模拟数据,并使用process_in_batches
将数据分成批次。对于每个批次,函数执行以下操作:-
使用
transform_data
转换批次 -
打印批处理,以显示加载前的内容
-
使用
load_data
模拟加载批次
-
现在,让我们从批处理转向流式处理模式。在流式处理中,数据在到达时被处理,而不是在预定义的批次中处理。
以流式模式摄取数据
流式摄取是一种数据处理技术,通过该技术,数据在生成时实时收集、处理并加载到系统中。与批处理摄取不同,批处理摄取是在预定的时间间隔内积累数据进行处理,流式摄取则是持续处理数据,允许组织立即分析和采取行动。例如,一家公司可以在客户交易发生时就处理交易数据,从而实现实时的洞察和决策。这种方法对于那些需要实时数据分析的组织尤其有用,比如金融交易、欺诈检测或传感器数据监控等领域。
流数据摄取具有优势,因为它可以实现数据的即时处理,减少延迟并使组织能够快速响应变化的环境条件。这在及时响应至关重要的场景中尤其有益,比如检测异常、个性化用户体验或应对实时事件。此外,流式处理可以通过将处理负载均匀地分布在时间上,而不是集中在特定的批处理窗口内,从而提高资源利用效率。在基于云的环境中,这也可以转化为成本节约,因为可以动态扩展资源以匹配实时数据流。对于数据流不规则或不可预测的组织,流数据摄取提供了一种灵活、响应迅速且可扩展的数据处理和分析方法。让我们来看一下它的一些优点和缺点。
优势与劣势
流数据摄取具有几个明显的优势,使其成为某些数据处理需求的必要选择:
-
其中一个主要的好处是能够从数据中获取实时洞察。这种即时性对于诸如欺诈检测、实时分析和动态定价等应用至关重要,其中及时的数据是至关重要的。
-
流数据摄取支持连续的数据处理,使系统能够在数据到达时进行处理,从而减少延迟并提高响应能力。
-
这种方法具有高度可扩展性,能够有效管理来自多个来源的高速数据流而不会产生显著延迟。
然而,流数据摄取也面临一些挑战:
-
实施流数据摄取系统可能是复杂的,需要精密的基础设施和专门的工具来有效管理数据流。
-
持续处理需要不断的计算资源,这可能是昂贵且资源密集型的。
-
在流式环境中确保数据一致性和准确性可能很困难,因为数据不断涌入,并且可能会出现乱序或重复记录。
让我们来看一下批量模式下数据摄取的常见应用场景。
流数据摄取的常见应用场景
虽然批量处理非常适合周期性的大规模数据更新和转换,但流数据摄取对实时数据分析和需要即时洞察的应用至关重要。以下是流数据摄取的常见应用场景。
实时欺诈检测和安全监控
金融机构使用流数据来实时检测欺诈活动,分析交易数据。即时异常检测帮助在欺诈造成重大损失之前予以阻止。流数据还用于网络安全领域,以便立即检测和应对威胁。对网络流量、用户行为和系统日志的持续监控有助于在发生安全漏洞时进行识别和缓解。
物联网和传感器数据
在制造业中,来自机器设备传感器的流式数据可以实现预测性维护。通过持续监控设备健康状况,公司能够防止设备故障并优化维护计划。
物联网和传感器领域的另一个有趣应用是智慧城市。来自城市中各种传感器(如交通、天气、污染等)的流式数据有助于实时管理城市运营,改善交通管理、应急响应等服务。
在线推荐与个性化
流式数据使电子商务平台能够根据用户当前的浏览和购买行为,向用户提供实时推荐。这提升了用户体验,并增加了销售额。像 Netflix 和 Spotify 这样的平台利用流式数据在用户与服务互动时更新推荐,实时提供个性化内容建议。
金融市场数据
股票交易员依赖流式数据获取关于股价和市场状况的最新信息,从而做出明智的交易决策。自动化交易系统利用流式数据根据预设标准执行交易,这需要实时数据处理以确保最佳性能。
电信
电信公司使用流式数据实时监控网络性能和使用情况,确保服务质量最佳并能迅速解决问题。流式数据还帮助跟踪客户互动和服务使用情况,实现个性化客户支持,提升整体体验。
实时物流与供应链管理
来自 GPS 设备的流式数据使物流公司能够实时追踪车辆位置并优化路线,提高交付效率。实时库存跟踪帮助企业维持最佳库存水平,减少过度库存和缺货现象,同时确保及时补货。
电子商务平台中的流式数据摄取
流式数据摄取是一个有序的过程,涉及多个关键步骤:数据提取、数据转换、数据加载以及监控与告警。为了说明这些步骤,让我们探讨一个电子商务平台的用例,该平台需要实时处理和分析用户活动数据,以实现个性化推荐和动态库存管理。
一个电子商务平台需要收集、转换并加载来自各种来源的用户活动数据,如网站点击、搜索查询和购买交易,将其导入到中央系统中。这些数据将用于生成实时个性化推荐、监控用户行为,并动态管理库存。
数据提取
第一步是识别数据将从哪些来源提取。对于电子商务平台,这些来源包括 Web 服务器、移动应用程序和第三方分析服务。这些来源包含关键信息,如用户点击、搜索查询和交易详情。一旦确定了数据来源,就可以使用流式连接器或 API 进行数据采集。这涉及到设置数据管道,从 Web 服务器、移动应用程序和分析服务中实时提取数据。提取的数据随后会流式传输到如 Apache Kafka 或 AWS Kinesis 等处理系统。
数据转换
提取的数据通常包含不一致和噪音。实时数据清洗会过滤掉不相关的信息,处理缺失值并纠正错误。对于电子商务平台来说,这确保了用户活动记录的准确性,并且对分析有意义。清洗之后,数据会进行诸如解析、丰富和聚合等转换。例如,电子商务平台可能会解析用户点击流数据,以识别浏览模式,用产品详情丰富交易数据,并聚合搜索查询以识别流行的产品。转换后的数据必须映射到目标系统的架构中。这涉及到将数据字段与实时分析系统的结构对齐。例如,用户活动数据可能会映射到表示会话、产品和用户档案的表格中,确保与现有数据模型的无缝集成。
数据加载
转换后的数据通过 Apache Flink 或 Apache Spark Streaming 等工具持续处理。持续处理使电子商务平台能够高效地处理高速数据流,实时执行转换和聚合。一旦处理完成,数据会被加载到目标存储系统中,如实时数据库或分析引擎,在那里可以进行个性化推荐和动态库存管理。
监控与告警
为确保流式数据摄取过程顺利且一致地运行,使用 Prometheus 或 Grafana 等监控工具。这些工具提供有关数据摄取管道性能和健康状况的实时洞察,能够识别任何故障或性能瓶颈。实现告警机制至关重要,以便及时发现并解决流式数据摄取过程中的问题。对于电子商务平台来说,这确保了数据流中断能迅速得到解决,从而保持数据管道的完整性和可靠性。
流式数据摄取示例
如我们所说,在流式处理中,数据是随着到达而被处理,而不是按照预定义的批次进行处理。让我们修改批处理示例,转向流式处理范式。为了简化起见,我们将持续生成数据,数据一到达就立即处理,进行转换,然后加载:
-
generate_mock_data
函数使用生成器持续生成记录,并模拟每条记录之间的延迟:def generate_mock_data(): while True: record = { 'id': random.randint(1, 1000), 'value': random.random() * 100 } yield record time.sleep(0.5) # Simulate data arriving every 0.5 seconds
-
process_stream
函数处理来自数据生成器的每条记录,而无需等待批次填充:def process_stream(run_time_seconds=10): start_time = time.time() for record in generate_mock_data(): transformed_record = transform_data(record) load_data(transformed_record) # Check if the run time has exceeded the limit if time.time() – start_time > run_time_seconds: print("Time limit reached. Terminating the stream processing.") break
-
transform_data
函数在每条记录到达时分别进行转换:def transform_data(record): transformed_record = { 'id': record['id'], 'value': record['value'], 'transformed_value': record['value'] * 1.1 # Example transformation } return transformed_record
-
load_data
函数模拟通过处理每一条记录来加载数据,而不是像以前那样在批次中处理每一条记录:def load_data(record): print(f"Loading record into database: {record}")
让我们从实时处理转向半实时处理,可以将其视为在短时间间隔内的批处理。这通常称为微批处理。
实时与半实时数据摄取
实时数据摄取是指几乎即时地收集、处理和加载数据的过程,正如我们所讨论的那样。这种方法对于需要立即洞察和行动的应用程序至关重要,例如欺诈检测、股票交易和实时监控系统。实时数据摄取提供了最低延迟,使企业能够在事件发生时立即做出反应。然而,它需要强大的基础设施和持续的资源分配,这使得其维护复杂且可能昂贵。
半实时数据摄取,另一方面,也称为接近实时数据摄取,涉及在最小延迟下处理数据,通常是几秒钟或几分钟,而不是即时处理。这种方法在实时和批处理之间达成平衡,提供及时的洞察,同时减少了与真正的实时系统相关的资源强度和复杂性。半实时数据摄取适用于社交媒体监控、客户反馈分析和运营仪表板等应用,其中接近即时的数据处理是有益的,但并非至关重要的时间敏感。
接近实时摄取的常见用例
让我们来看一些常见的用例,其中可以使用接近实时的数据摄取。
实时分析
流式处理使组织能够持续监控数据流动,允许实时仪表板和可视化。这在金融行业尤为重要,因为股票价格、市场趋势和交易活动需要实时跟踪。它还允许即时生成报告,促进及时决策,并减少数据生成与分析之间的延迟。
社交媒体和情感分析
企业实时跟踪社交媒体上的提及和情感,以管理品牌声誉并迅速回应客户反馈。流式数据使得可以持续分析公众对品牌、产品或事件的情感,提供即时洞察,这些洞察可能影响营销和公关策略。
客户体验提升
近实时处理使支持团队能够访问客户问题和行为的最新信息,从而更快更准确地回应客户询问。企业还可以利用近实时数据更新客户档案,并在客户与网站或应用程序互动后不久触发个性化的营销信息,如电子邮件或通知。
带有示例的半实时模式
从实时数据处理过渡到半实时数据处理涉及调整示例,引入更结构化的方式来处理数据更新,而不是在每条记录到达时立即处理。可以通过在短时间间隔内批量处理数据更新来实现,这样可以更高效地处理数据,同时保持响应式的数据处理管道。让我们看看这个示例,和往常一样,您可以在 GitHub 仓库中找到代码 github.com/PacktPublishing/Python-Data-Cleaning-and-Preparation-Best-Practices/blob/main/chapter01/3.semi_real_time.py
:
-
连续生成模拟数据,与之前的示例没有变化。这个过程会持续生成模拟数据记录,并有轻微的延迟(
time.sleep(0.1)
)。 -
对于半实时处理,我们可以使用一个双端队列(deque)来缓存传入的记录。这个功能会在指定的时间间隔过去,或者缓冲区达到指定大小(
batch_size
)时处理记录。然后,它将双端队列转换为列表(list(buffer)
),再传递给transform_data
,确保数据是以批处理的方式进行处理:def process_semi_real_time(batch_size, interval): buffer = deque() start_time = time.time() for record in generate_mock_data(): buffer.append(record)
-
检查间隔是否已过,或缓冲区大小是否已达到:
if (time.time() - start_time) >= interval or len(buffer) >= batch_size:
-
处理并清理缓冲区:
transformed_batch = transform_data(list(buffer)) # Convert deque to list print(f"Batch of {len(transformed_batch)} records before loading:") for rec in transformed_batch: print(rec) load_data(transformed_batch) buffer.clear() start_time = time.time() # Reset start time
-
然后,我们转换批次中的每一条记录。与之前的示例没有变化,我们加载数据。
当您运行此代码时,它会持续生成模拟数据记录。记录会被缓冲,直到指定的时间间隔(interval
)过去,或者缓冲区达到指定的大小(batch_size
)。一旦条件满足,缓冲的记录将作为一个批次进行处理、转换,然后“加载”(打印)到模拟数据库中。
在讨论适合批处理、流式处理或半实时流处理的不同类型数据源时,必须考虑这些数据源的多样性和特性。数据可以来自多种来源,例如数据库、日志、物联网设备、社交媒体或传感器,正如我们将在下一部分看到的那样。
数据源解决方案
在现代数据分析和处理的世界中,可供摄取的数据源种类繁多,涵盖了从传统文件格式(如 CSV、JSON 和 XML)到强大的数据库系统(包括 SQL 和 NoSQL 系统)的广泛范围。此外,还包括动态 API(如 REST),以便实时获取数据。像 Kafka 这样的消息队列提供了可扩展的解决方案来处理事件驱动的数据,而 Kinesis 和 pub/sub 等流媒体服务则支持连续的数据流,这对于要求即时洞察的应用至关重要。理解并有效利用这些多样化的数据摄取来源,是构建支持广泛分析和操作需求的强大数据管道的基础。
让我们从事件处理开始。
事件数据处理解决方案
在实时处理系统中,数据几乎是即时摄取、处理并响应的,正如我们之前讨论过的。实时处理系统通常使用消息队列来处理传入的数据流,并确保数据按接收顺序处理,不会产生延迟。
以下 Python 代码展示了使用消息队列处理消息的基本示例,这是实时和半实时数据处理系统中的基础概念。Python queue
模块中的 Queue
类用于创建队列——一个遵循先进先出(FIFO)原则的数据结构。在队列中,消息(例如message 0
、message 1
等)会按照顺序被添加。这模拟了事件或任务的生成,需要按到达的顺序进行处理。我们来看看代码的每个部分。你可以在 github.com/PacktPublishing/Python-Data-Cleaning-and-Preparation-Best-Practices/blob/main/chapter01/4.work_with_queue.py
找到完整代码文件:
-
read_message_queue()
函数使用来自queue
模块的Queue
类初始化一个队列对象q
:def read_message_queue(): q = Queue()
-
这个循环将 10 条消息添加到队列中。每条消息是一个格式为
message i
的字符串,其中i
从 0 到 9 不等:for i in range(10): # Mocking messages q.put(f"message {i}")
-
这个循环会持续从队列中获取并处理消息,直到队列为空。
q.get()
从队列中获取消息,q.task_done()
表示已处理完获取的消息:while not q.empty(): message = q.get() process_message(message) q.task_done() # Signal that the task is done
-
以下函数接收一个消息作为输入,并将其打印到控制台,模拟消息的处理:
def process_message(message): print(f"Processing message: {message}")
-
调用
read_message_queue
函数:read_message_queue()
在这里,read_message_queue
函数从队列中读取消息,并使用 process_message
函数逐一处理这些消息。这演示了基于事件的系统如何处理任务——通过将它们放入队列并在任务变得可用时进行处理。
while not q.empty()
循环确保每条消息都按照加入队列的顺序被处理。这在许多现实世界的应用中至关重要,例如处理用户请求或日志时,处理顺序非常重要。
q.task_done()
方法表示消息已被处理。在现实世界的系统中,这一点非常重要,因为跟踪任务完成情况对于确保系统的可靠性和正确性至关重要,尤其是在有多个工作线程或线程的系统中。
在现实世界的应用中,消息队列通常会与更复杂的数据流平台集成,以确保可扩展性、容错性和高可用性。例如,在实时数据处理中,像 Kafka 和 AWS Kinesis 这样的平台就发挥了作用。
使用 Apache Kafka 摄取事件数据
有多种技术可用于摄取和处理事件数据。我们将讨论的一种技术是 Apache Kafka。Kafka 是一个开源的分布式事件流平台,最初由 LinkedIn 开发,后来捐赠给了 Apache 软件基金会。它被设计用来实时处理大量数据,并提供一个可扩展、容错的系统,用于处理和存储数据流。
图 1.1 – Apache Kafka 的组件
让我们来看一下 Apache Kafka 的不同组件:
-
摄取😗:可以使用 Kafka 生产者将数据流摄取到 Kafka 中。生产者是将数据写入 Kafka 主题的应用程序,Kafka 主题是可以存储和组织数据流的逻辑通道。
-
处理:Kafka 可以使用 Kafka Streams 处理数据流,Kafka Streams 是一个用于构建实时流处理应用程序的客户端库。Kafka Streams 允许开发人员构建自定义的流处理应用程序,可以对数据流进行转换、聚合和其他操作。
-
存储😗:Kafka 将数据流存储在分布式的、容错的集群中,这些集群被称为 Kafka 经纪人(brokers)。经纪人将数据流存储在分区中,这些分区在多个经纪人之间进行复制,以确保容错性。
-
消费😗:可以使用 Kafka 消费者从 Kafka 获取数据流。消费者是从 Kafka 主题读取数据并根据需要处理数据的应用程序。
可以使用多个库与 Apache Kafka 进行交互;我们将在下一节中探讨其中最流行的几个。
应该使用哪个库来处理你的使用案例?
Kafka-Python
是 Kafka 协议的纯 Python 实现,提供了一个更加 Pythonic 的接口,用于与 Kafka 交互。它设计简洁、易于使用,尤其适合初学者。它的主要优点之一就是简便性,相比其他 Kafka 库,它更易于安装和使用。Kafka-Python 灵活且非常适合小型到中型应用,提供了进行基本 Kafka 操作所需的必要功能,而不涉及额外的复杂依赖。由于它是纯 Python 库,因此不依赖于任何超出 Python 本身的外部库,从而简化了安装和设置过程。
Confluent-kafka-python
是由 Confluent(Kafka 的原创开发者)开发并维护的一个库。它以高性能和低延迟能力而著称,利用 librdkafka
C 库进行高效操作。该库提供了类似 Java Kafka 客户端的广泛配置选项,并与 Kafka 的功能集高度契合,常常率先支持 Kafka 的新特性。它特别适用于生产环境,在性能和稳定性至关重要的情况下,是处理高吞吐量数据流和确保关键应用中可靠消息处理的理想选择。
从事件数据处理转向数据库涉及将重点从实时数据流转移到持久数据存储和检索。事件数据处理强调处理连续的数据流,以便快速获得洞察或采取行动,而数据库则是结构化的存储库,旨在长期存储和管理数据。
从数据库中摄取数据
数据库,无论是关系型还是非关系型,都是数据管理系统的基础组成部分。经典数据库和 NoSQL 数据库是两种不同类型的数据库管理系统,它们在架构和特性上有所不同。经典数据库,也称为关系型数据库,将数据存储在具有固定模式的表格中。经典数据库非常适合需要复杂查询和事务一致性的应用,例如金融系统或企业应用。
另一方面,NoSQL 数据库不会将数据存储在具有固定模式的表格中。它们采用基于文档的方式,以灵活的模式格式存储数据。它们设计为可扩展并能处理大量数据,重点是高性能的数据检索。NoSQL 数据库非常适合需要高性能和可扩展性的应用,例如实时分析、内容管理系统和电子商务平台。
让我们从关系型数据库开始。
从关系型数据库执行数据摄取
关系数据库在批量 ETL 过程中非常有用,其中需要将来自各种源的结构化数据进行整合、转换并加载到数据仓库或分析系统中。在处理之前,基于 SQL 的操作可以有效地进行数据连接和聚合。让我们尝试了解 SQL 数据库如何使用表格、行和列来表示数据,使用代码示例。我们将使用 Python 字典来模拟基本的 SQL 数据库交互,以表示表格和行。您可以在github.com/PacktPublishing/Python-Data-Cleaning-and-Preparation-Best-Practices/blob/main/chapter01/5.sql_databases.py
看到完整的代码示例:
-
我们创建一个
read_sql
函数,模拟从 SQL 表格中读取行,这里表示为一个字典列表,其中每个字典对应表中的一行:def read_sql(): # Simulating a SQL table with a dictionary sql_table = [ {"id": 1, "name": "Alice", "age": 30}, {"id": 2, "name": "Bob", "age": 24}, ] for row in sql_table: process_row(row)
-
process_row
函数将一个行(字典)作为输入,并打印其内容,模拟从 SQL 表格中处理行的过程:def process_row(row): print(f"Processing row: id={row['id']}, name={row['name']}, age={row['age']}") read_sql()
-
让我们以正确的格式打印我们的 SQL 表格:
print(f"{'id':<5} {'name':<10} {'age':<3}") print("-" * 20) # Print each row for row in sql_table: print(f"{row['id']:<5} {row['name']:<10} {row['age']:<3}")
这将打印如下输出:
id name age ------------------ 1 Alice 30 2 Bob 24
从前面的例子中学习的关键是理解 SQL 数据库通过由行和列组成的表来结构化和管理数据,以及如何通过编程方式高效检索和处理这些行。这些知识是至关重要的,因为它为任何应用程序中的有效数据库管理和数据操作奠定了基础。
在实际应用程序中,这种交互通常由像Java 数据库连接(JDBC)或开放数据库连接(ODBC)这样的库和驱动程序实现,它们提供了连接和查询数据库的标准方法。这些库通常被 Python 中的更高级别框架或库包装,使开发人员能够从各种 SQL 数据库中导入数据,而不必担心底层连接细节。可以使用多个库与 Python 交互 SQL 数据库;我们将在下一节探讨最流行的几个。
对于您的用例应该使用哪个库?
让我们探索 Python 中用于与 SQL 数据库交互的不同库,并理解何时使用每个库:
-
SQLite (sqlite3)非常适合小到中型应用程序、本地存储和原型设计。它的零配置、无服务器架构使其非常适合轻量级、嵌入式数据库需求和快速开发周期。在不需要完整数据库服务器开销的场景中特别有用。避免在需要高并发或大量写操作的应用程序中使用 sqlite3,或者多用户需要同时访问数据库的场景。它不适合大规模应用或需要强大安全功能和高级数据库功能的场景。
-
SQLAlchemy 适用于需要对原始 SQL 进行高度抽象、支持多种数据库引擎以及复杂查询和数据模型的应用程序。它非常适合需要灵活性、可扩展性,并且能够在不同数据库之间切换而无需做大量代码修改的大规模生产环境。避免在小型轻量级应用程序中使用 SQLAlchemy,因为它的全面 ORM 功能会带来不必要的开销。如果您需要直接、低级地访问特定数据库的功能,并且能够编写原始 SQL 查询,那么像 sqlite3、Psycopg2 或 MySQL Connector/Python 这样的简单数据库适配器可能会更合适。
-
Psycopg2 是与 PostgreSQL 数据库交互的首选工具,适用于需要利用 PostgreSQL 高级功能(如 ACID 合规性、复杂查询和丰富数据类型)的应用程序。它非常适合需要可靠性和效率来处理 PostgreSQL 数据库的生产环境。如果您的应用程序不与 PostgreSQL 交互,请避免使用 Psycopg2。如果您需要与多个数据库系统兼容或需要更高层次的抽象,请考虑使用 SQLAlchemy。另外,对于不需要完整 PostgreSQL 设置的轻量级应用程序,Psycopg2 可能不是最佳选择。
-
mysql-connector-python
)非常适合需要与 MySQL 数据库直接交互的应用程序。它适用于需要兼容性并获得 Oracle 官方支持的环境,也适用于利用 MySQL 功能(如事务管理和连接池)的应用程序。如果您的应用程序需要与多个数据库系统兼容或需要更高层次的抽象,请不要使用 MySQL Connector/Python。对于那些不需要完整 MySQL 设置的简单应用程序,或者不特别需要 MySQL 功能的应用程序,可以考虑其他轻量级的替代方案。
在了解了与 SQL 数据库交互的各种库及其使用场景后,探索在传统关系型 SQL 数据库可能不太适用的情况下的替代方案同样重要。这引出了 NoSQL 数据库,它们提供了处理非结构化或半结构化数据的灵活性、可扩展性和性能。让我们深入研究与流行的 NoSQL 数据库进行交互的关键 Python 库,并探讨何时以及如何有效地使用它们。
从 NoSQL 数据库进行数据摄取
非关系型数据库可以用于存储和处理大量半结构化或非结构化数据的批量操作。它们在模式可以演变或需要以统一方式处理多种数据类型时尤其有效。NoSQL 数据库在流式处理和半实时工作负载中表现出色,因为它们能够处理高吞吐量和低延迟的数据摄取。它们通常用于捕获和处理来自 IoT 设备、日志、社交媒体动态以及其他生成连续数据流的来源的实时数据。
提供的 Python 代码模拟了一个使用字典的 NoSQL 数据库,并处理每个键值对。让我们来看看代码的每个部分:
-
process_entry
函数从数据存储中获取一个键及其关联的值,并打印出一条格式化的消息,展示该键值对的处理过程。它提供了一种简单的方法来查看或处理单个条目,突出显示如何基于键访问和操作数据:def process_entry(key, value): print(f"Processing key: {key} with value: {value}")
-
以下函数以表格格式打印整个
data_store
字典:def print_data_store(data_store): print(f"{'Key':<5} {'Name':<10} {'Age':<3}") print("-" * 20) for key, value in data_store.items(): print(f"{key:<5} {value['name']:<10} {value['age']:<3}")
它首先打印
Key
、Name
和Age
的列标题,然后跟随一条分隔线以增加清晰度。接着,它遍历data_store
字典中的所有键值对,打印每个条目的键、名称和年龄。这个函数有助于可视化当前数据存储的状态。数据的初始状态如下:Initial Data Store: Key Name Age ----------------------- 1 Alice 30 data_store dictionary:
def create_entry(data_store, key, value):
data_store[key] = value
return data_store
It takes a key and a value, then inserts the value into `data_store` under the specified key. The updated `data_store` dictionary is then returned. This demonstrates the ability to add new data to the store, showcasing the creation aspect of `update_entry` function updates an existing entry in the `data_store` dictionary:
def update_entry(data_store, key, new_value):
if key in data_store:
data_store[key] = new_value
return data_store
It takes a key and `new_value`, and if the key exists in the `data_store` dictionary, it updates the corresponding value with `new_value`. The updated `data_store` dictionary is then returned. This illustrates how existing data can be modified, demonstrating the update aspect of CRUD operations.
-
以下函数从
data_store
字典中移除一个条目:def delete_entry(data_store, key): if key in data_store: del data_store[key] return data_store
它接受一个键,如果该键在
data_store
字典中找到,则删除相应的条目。更新后的data_store
字典会被返回。 -
以下函数将所有过程整合在一起:
def read_nosql(): data_store = { "1": {"name": "Alice", "age": 30}, "2": {"name": "Bob", "age": 24}, } print("Initial Data Store:") print_data_store(data_store) # Create: Adding a new entry new_key = "3" new_value = {"name": "Charlie", "age": 28} data_store = create_entry(data_store, new_key, new_value) # Read: Retrieving and processing an entry print("\nAfter Adding a New Entry:") process_entry(new_key, data_store[new_key]) # Update: Modifying an existing entry update_key = "1" updated_value = {"name": "Alice", "age": 31} data_store = update_entry(data_store, update_key, updated_value) # Delete: Removing an entry delete_key = "2" data_store = delete_entry(data_store, delete_key) # Print the final state of the data store print("\nFinal Data Store:") print_data_store(data_store)
这段代码演示了 NoSQL 数据库的核心原则,包括架构灵活性、键值对存储和基本的 CRUD 操作。它从
read_nosql()
函数开始,该函数使用字典data_store
模拟了一个 NoSQL 数据库,其中每个键值对代表一个唯一的标识符和相关的用户信息。最初,print_data_store()
函数以表格格式显示数据,突出展示了 NoSQL 系统固有的架构灵活性。接着,代码演示了 CRUD 操作。首先,create_entry()
函数添加了一个新条目,展示了如何将新数据插入存储中。随后,process_entry()
函数检索并打印新添加条目的详细信息,展示了读取操作。接下来,update_entry()
函数修改了一个现有条目,展示了 NoSQL 数据库的更新能力。delete_entry()
函数则用于删除一个条目,展示了如何从存储中删除数据。最后,再次打印更新后的data_store
字典,清晰地展示了数据在这些操作中的变化过程。 -
让我们执行整个过程:
read_nosql()
这将返回最终的数据存储:
Final Data Store: Key Name Age ----------------------- 1 Alice 31 2 Charlie 28
在前面的示例中,我们演示了如何使用 Python 与一个模拟的 NoSQL 系统进行交互,以便展示 NoSQL 数据库的核心原则,例如架构灵活性、键值对存储和基本的 CRUD 操作。现在我们可以更好地理解 NoSQL 数据库在数据建模和高效处理非结构化或半结构化数据方面与传统 SQL 数据库的区别。
有多个库可以用来与 NoSQL 数据库进行交互。在接下来的章节中,我们将探索其中最受欢迎的几个。
你应该根据自己的使用案例选择哪一个库?
让我们探索在 Python 中与 NoSQL 数据库交互的不同库,并了解何时使用每一个:
-
pymongo
是 MongoDB 的官方 Python 驱动,MongoDB 是一种因其灵活性和可扩展性而广受欢迎的 NoSQL 数据库。pymongo
允许 Python 应用程序与 MongoDB 无缝互动,提供了一个简洁的 API 来执行 CRUD 操作、管理索引以及执行复杂查询。pymongo
特别受到欢迎,因为它易于使用且与 Python 数据结构兼容,使其适用于从简单原型到大规模生产系统的各种应用。 -
cassandra-driver
(Cassandra):cassandra-driver
库为 Python 应用程序提供了直接访问 Apache Cassandra 的能力,Cassandra 是一个高度可扩展的 NoSQL 数据库,设计用于处理分布式普通服务器上的大量数据。Cassandra 的架构针对写密集型工作负载进行了优化,并提供了可调的一致性级别,适用于实时分析、物联网数据及其他需要高可用性和容错性的应用。
从数据库过渡到文件系统涉及将重点从结构化的数据存储和检索机制转向更灵活和多功能的存储解决方案。
从基于云的文件系统执行数据摄取
云存储是一种服务模型,允许通过互联网远程维护、管理和备份数据。它涉及将数据存储在远程服务器上,并通过互联网从任何地方访问,而不是存储在本地设备上。云存储彻底改变了我们存储和访问数据的方式。它为个人和组织提供了一种灵活且可扩展的解决方案,使他们能够存储大量数据,无需投资物理硬件。这对于确保数据始终可访问并且可以轻松共享尤其有用。
Amazon S3、Microsoft Azure Blob Storage 和 Google Cloud Storage 都是基于云的对象存储服务,允许你在云中存储和检索文件。基于云的文件系统因多个原因变得越来越流行。
首先,它们提供了一种灵活且可扩展的存储解决方案,可以轻松适应组织不断变化的需求。这意味着,随着数据量的增长,可以在不需要大量资本投资或物理基础设施更改的情况下增加额外的存储容量。因此,它可以帮助减少与维护和升级本地存储基础设施相关的资本支出和运营成本。
其次,基于云的文件系统提供高水平的可访问性和可用性。数据存储在云中,用户可以从任何有互联网连接的地方访问它,这使得跨不同团队、部门或地点的协作和信息共享变得更加容易。此外,基于云的文件系统设计了冗余和故障转移机制,确保数据在硬件故障或停机事件发生时仍然可用。最后,它们提供增强的安全功能,以防止未经授权的访问、数据泄露或数据丢失。云服务提供商通常具备先进的安全协议、加密和监控工具来保护数据,并确保遵守数据隐私法规。
云存储系统中的文件本质上与本地设备上的文件相同,但它们存储在远程服务器上并通过互联网访问。然而,这些文件在云存储系统中是如何组织的呢?接下来我们来讨论这个问题。
在云存储系统中组织文件
在云存储中组织文件的主要方法之一是使用文件夹结构,这类似于本地文件系统。用户可以创建文件夹和子文件夹,以系统地分类和存储文件。我们来看一下最佳实践:
-
创建一个符合逻辑且直观的层级结构,反映出你的工作方式或项目结构是至关重要的。这涉及设计一个与工作流程相匹配的文件夹结构,使文件的定位和管理更加简便。例如,你可以为不同的部门、项目或客户创建主文件夹,并为特定任务或文档类型创建子文件夹。这种层级组织不仅通过减少寻找文件所需的努力节省时间,还通过提供一个清晰且一致的框架,提升了团队成员之间的协作,便于大家快速导航。
-
使用一致的命名规范来命名文件夹和文件对于确保云存储中的文件便捷检索和保持有序至关重要。标准化的命名方案有助于避免混淆,减少错误,并加快查找特定文档的过程。例如,采用如
YYYY-MM-DD_ 项目名称 _ 文档类型
这样的格式,可以提供即时的上下文信息,并使排序和搜索变得更加直接。一致的命名还促进了自动化和与其他工具的集成,因为可预测的文件名更易于被脚本和应用程序处理。 -
按项目或客户对文件进行分组是保持相关文档集中和简化项目管理的有效方法。这种方法涉及为每个项目或客户创建专门的文件夹,所有相关文件,如合同、通信和交付物,都存储在这些文件夹中。
-
许多云存储系统允许通过关键字或元数据为文件加标签,这大大增强了文件分类和搜索功能。标签本质上是你可以附加到文件上的标签,使得根据特定标准对文档进行分组和查找变得更加容易。元数据包括详细信息,如作者、日期、项目名称和文件类型,这些信息提供了额外的上下文,有助于更精确的搜索。通过使用相关标签和全面的元数据,你可以快速筛选并定位文件,无论它们位于文件夹层级的哪个位置。这种做法在大型存储系统中尤为有用,因为在这些系统中,传统的文件夹结构可能会变得笨重。
从讨论云存储系统开始,焦点现在转向探索 API 所提供的功能和集成机会。
APIs
近年来,API 变得越来越受欢迎,因为它们能够实现不同系统和服务之间的无缝通信和集成。API 为开发者提供了一种标准化且灵活的方式,能够访问其他系统的数据和功能,使他们能够轻松构建利用现有资源的新应用和服务。API 已成为现代软件开发的基础构件,广泛应用于各个行业和领域。
现在我们理解了 API 的含义,让我们继续了解requests
Python 库,它使开发人员能够以编程方式访问和操作远程服务器上的数据。
requests
库
在使用 Python 与 API 进行交互时,requests
库是用于向 API 和其他网络服务发送 HTTP 请求的首选 Python 库。它使得用 Python 发送 HTTP/1.1 请求变得简单,并提供了许多方便的功能来处理 HTTP 响应。
运行以下命令来安装requests
库:
pip install requests==2.32.3
让我们快速看看如何使用这个库:
-
导入
requests
库:import requests
-
指定 API 端点的 URL:
url = "https://jsonplaceholder.typicode.com/posts"
-
对 API 端点发起
GET
请求:response = requests.get(url)
-
获取响应内容:
print(response.content)
在这里,我们向jsonplaceholder.typicode.com/posts
的 API 端点发起了GET
请求,并将response
对象存储在response
变量中。然后,我们可以使用response
对象的content
属性打印响应内容。requests
库提供了许多其他方法和功能来发起 HTTP 请求,包括对POST
、PUT
、DELETE
等 HTTP 方法的支持、处理头信息和 Cookies,以及处理重定向和身份验证。
现在我们已经解释了requests
库,让我们来看看一个具体的例子,如何从Cocktail DB
API 中获取玛格丽塔鸡尾酒的数据,这可以说明如何将实际的网页请求应用到访问和整合实时数据源到应用程序中。
学习如何制作玛格丽塔鸡尾酒!
本用例演示了如何使用 Python 从Cocktail DB
API 中检索鸡尾酒数据。如果你想提高你的调酒技能并给朋友留下深刻印象,你可以使用开放 API 获取任何鸡尾酒所需成分的实时信息。为此,我们将使用Cocktail DB
API 和requests
库,看看我们需要哪些成分来制作玛格丽塔:
-
定义 API 端点 URL。我们正在向 Cocktail DB API 端点发出请求,搜索名称为
margarita
的鸡尾酒:url = "https://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita"
-
发起 API 请求。我们将 API 端点 URL 定义为字符串,并将其传递给
requests.get()
函数来发起GET
请求:response = requests.get(url)
-
检查请求是否成功(状态码
200
),并获取数据。API 响应以 JSON 字符串形式返回,我们可以通过调用response.json()
方法来提取它。然后,我们将这个 JSON 数据赋值给一个名为data
的变量:if response.status_code == 200: # Extract the response JSON data data = response.json() # Check if the API response contains cocktails data if 'drinks' in data: # Create DataFrame from drinks data df = pd.DataFrame(data['drinks']) # Print the resulting DataFrame print(df.head()) else: print("No drinks found.")
-
如果请求不成功,请打印此错误信息:
else: print(f"Failed to retrieve data from API. Status code: {response.status_code}")
你可以将margarita
搜索参数替换为其他鸡尾酒名称或成分,以获取不同饮品的数据。
到这里,我们已经结束了第一章。让我们总结一下到目前为止学到的内容。
总结
在本章中,我们涵盖了现代计算和数据管理中的重要技术。我们首先讨论了批量摄取,这是一种在预定时间间隔内收集和处理大量数据的方法,为数据流可预测的组织提供了高效且具成本效益的解决方案。与之相对,我们探讨了流式摄取,它允许数据实时处理,从而能够即时分析并迅速应对变化的条件。接着我们介绍了如 Kafka 等流式服务,用于实时数据处理。随后我们讲解了 SQL 和 NoSQL 数据库——如 PostgreSQL、MySQL、MongoDB 和 Cassandra——并突出了它们在结构化和灵活数据存储方面的优势。我们还探索了像 REST 这样的 API,以实现系统的无缝集成。此外,我们深入讨论了文件系统、文件类型及其属性,并介绍了如 Amazon S3 和 Google Cloud Storage 等云存储解决方案,强调了可扩展性和数据管理策略。这些技术共同推动了当今数字生态系统中强大、可扩展且高效的应用程序。
在即将到来的章节中,我们将深入探讨数据质量的关键方面及其在构建可靠数据产品中的重要性。我们将探索为什么确保高数据质量对于做出明智的商业决策、提升客户体验和维持运营效率至关重要。
第二章:数据质量的重要性
你知道数据是许多重要商业决策的支柱吗?没有准确、完整、一致的信息,企业可能会做出错误的判断,这可能损害企业的声誉、客户关系及整体业务。不同数据集之间的一致性问题可能会造成混乱,阻碍有意义的分析。无关或过时的数据可能会误导决策者的判断,导致做出次优选择。另一方面,构建高质量的数据产品则是一个强有力的资产,能够帮助组织做出明智的决策、发现有价值的洞察、识别趋势、降低风险并获得竞争优势。
在本章中,我们将深入探讨以下话题:
-
为什么数据质量很重要
-
用于衡量数据产品中数据质量的不同维度
-
数据孤岛对数据质量的影响
技术要求
你可以在以下的 GitHub 仓库中找到本章的所有代码:
github.com/PacktPublishing/Python-Data-Cleaning-and-Preparation-Best-Practices/tree/main/chapter02
为什么数据质量很重要
让我来揭示一下为什么数据质量如此重要:
-
准确的数据能带来竞争优势:组织依赖数据来识别模式、趋势、偏好以及支配其生态系统的其他关键因素。如果你的数据质量不合格,结果分析和结论可能会失真,导致错误的决策,这可能会危及整个业务。
-
完整的数据是成本优化的基石:数据构成了自动化和优化的基础,若能得当地执行,能够提高生产力并降低费用。不完整或低质量的数据会导致瓶颈并增加成本。试想一下,如果数据录入标准更高,许多本可以避免的错误就不会浪费无数的人工时间去修正。
-
顶级数据能够带来长期忠诚的满意客户:每个企业的生命力依赖于满意的客户,客户的忠诚度能够确保企业的持续增长。关于客户的错误数据可能会导致个性化体验不匹配客户特征,甚至出现错误的账单和未满足的请求。这些失望的客户可能会把生意带到别处,导致公司面临生存困境。
-
合规的数据是避免不必要法律后果的必要条件:许多行业必须遵循有关数据精度、安全性和隐私的特定规则。遵守这些规则需要高质量的数据,以满足严格的指南,并防止法律处罚以及可能失去消费者信任。
-
为了避免数据孤岛,你需要信任你的数据:当企业中的多个实体必须协作利用数据时,确保数据的完整性至关重要。数据的不兼容或差异可能会妨碍合作,阻碍集成工作,并导致数据孤岛的形成。
-
数据质量实际上意味着信任:数据质量直接影响利益相关者对组织的信任和信誉。通过保持高质量的数据,组织可以在客户、合作伙伴和投资者之间建立信任。
现在我们更清楚数据质量为何重要,接下来进入下一部分,我们将深入探讨数据质量的不同维度。
数据质量的维度
如前所述,卓越的数据质量是构建明智决策和战略洞察力的基础。考虑到这一点,我们现在来探讨我们可以使用哪些关键绩效指标(KPIs)来衡量我们资产的数据质量。
完整性
完整性衡量数据的完整程度,即数据是否缺少任何值或字段。关键绩效指标可能包括缺失数据的百分比或每条记录缺失的数据点数。
以下代码将输出数据集中每列的完整性百分比。较高的百分比表示较高的完整性水平,而较低的百分比则表示更多缺失值:
-
我们将首先导入
pandas
库以处理数据集:import pandas as pd
-
接下来,我们创建一个包含以下列的示例数据集:
Name
(姓名)、Age
(年龄)、Gender
(性别)和City
(城市)。其中有些值故意缺失(用None
表示):data = { 'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'], 'Age': [25, 30, None, 28, 22], 'Gender': ['Female', 'Male', 'Male', 'Male', 'Female'], 'City': ['New York', 'Los Angeles', 'Chicago', None, 'San Francisco'] }
-
然后,我们创建一个 pandas DataFrame:
df = pd.DataFrame(data)
-
然后,我们将使用
isnull()
函数来识别每列的缺失值,并使用sum()
函数计算每列缺失值的总数:completeness = df.isnull().sum()
-
接下来,我们将计算完整性百分比:
total_records = len(df) completeness_percentage = (1- completeness / total_records) * 100
这将打印以下输出:
Completeness Check: Name 0 Age 1 Gender 0 City 1 Completeness Percentage: Name 100.0 Age 80.0 Gender 100.0 City 80.0
完整性检查显示每列缺失值的数量,完整性百分比表示每列缺失值相对于总记录数的比例。该输出表明,Name
(姓名)和Gender
(性别)列的完整性为 100%,而Age
(年龄)和City
(城市)列的完整性为 80%。
注释 – 完整性百分比
完整性百分比通过将缺失值的数量除以数据集中的总记录数,然后乘以 100 来计算。它表示缺失值相对于数据集大小的比例。
完整性百分比越高, 越好!
准确性
准确性通过将数据与可信来源或基准进行比较,来评估数据的正确性。
以下代码将根据实际值与期望值的比较输出准确度百分比:
-
我们首先加载所需的库:
import pandas as pd
-
接下来,我们创建一个名为
data
的示例数据集和一个名为reference_data
的参考数据集。两个数据集具有相同的结构(列:Name
、Age
、Gender
和City
):data = { 'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'], 'Age': [25, 30, 28, 28, 22], 'Gender': ['Female', 'Male', 'Male', 'Male', 'Female'], 'City': ['New York', 'Los Angeles', 'Chicago', 'New York', 'San Francisco'] } # Reference dataset for accuracy comparison reference_data = { 'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'], 'Age': [25, 30, 29, 28, 22], 'Gender': ['Female', 'Male', 'Male', 'Male', 'Female'], 'City': ['New York', 'Los Angeles', 'Chicago', 'New York', 'San Francisco'] }
-
我们使用示例数据和参考数据分别创建两个名为
df
和reference_df
的 pandas 数据框:df = pd.DataFrame(data) reference_df = pd.DataFrame(reference_data)
-
我们创建一个
accuracy_check
变量,并将df
和reference_df
之间比较的结果赋值给它。此比较使用==
运算符,它为匹配的值返回True
,为不匹配的值返回False
:accuracy_check = df == reference_df
我们可以使用
==
运算符将实际值列与期望值列进行比较。 -
我们然后通过对每一列的
accuracy_check
数据框求平均值来计算准确率百分比。mean
操作将True
视为1
,将False
视为0
,因此它有效地计算了每一列中匹配值的百分比:accuracy_percentage = accuracy_check.mean() * 100
-
最后,我们打印结果:
# Display the accuracy results print("Accuracy Check:") print(accuracy_check) print("\nAccuracy Percentage:") print(accuracy_percentage)
输出如下:
Accuracy Check: Name Age Gender City 0 True True True True 1 True True True True 2 True False True True 3 True True True True 4 True True True True Accuracy Percentage: Name 100.0 Age 80.0 Gender 100.0 City 100.0
准确性检查显示
True
表示数据与参考数据集匹配,False
表示不匹配。准确率百分比表示每列中匹配值相对于记录总数的比例。该输出表示在这种情况下,Age
列是唯一需要更多关注的列。其他所有列的准确率为 100%。
注意 – 准确率百分比
准确率百分比可以通过对所有列的比较结果求平均值,并乘以 100 来计算。这个百分比代表了匹配数据值相对于总数据点数量的比例。
准确率越高,结果越好!
想知道如何构建基准数据集吗?
基准数据必须能够代表你要解决的任务。这意味着,取决于数据生命周期的不同阶段,基准数据的构建方式不同,所起的作用也不同。
构建基准数据集对于各种数据角色至关重要,包括数据工程师、数据分析师和机器学习从业者。对于数据工程师而言,基准数据对于数据验证和测试至关重要。好消息是,在大多数情况下,数据工程师可以通过历史数据构建基准标签,方法如下:
-
数据验证规则:建立验证规则和约束,以验证数据在流经管道时的准确性。
-
人工检查:手动检查数据样本以识别不一致性或错误,并创建经过验证和修正的数据集。这可以作为基准数据集。
数据分析师依赖基准数据来验证他们的发现的准确性,这些数据可以通过专家注释、历史数据和用户反馈获得,确保分析见解反映了现实世界的现象:
-
专家注释:如果处理的是非结构化或文本数据,领域专家可以手动为数据样本标注正确的标签或类别,作为分析的真实标签。
-
历史数据:使用具有良好文档化准确度的历史数据作为真实标签。这在分析趋势、模式或历史事件时尤其有价值。
-
调查和用户反馈:从调查或用户反馈中收集数据,以验证从数据中得出的见解和结论。这些可以作为定性真实标签。
最后,在机器学习的背景下,真实标签数据是模型训练和评估的基础:
-
手动标注:手动为数据样本添加注释,以创建标注数据集。这对于图像分类、情感分析或目标检测等任务很常见。
-
众包:使用众包平台收集来自多个人工工人的注释,他们共同建立真实标签数据。
-
现有数据集:许多机器学习任务从已被研究社区广泛使用的基准数据集中获益。你可以根据需要使用和更新这些数据集。
-
领域专家标签:请咨询领域专家,为数据提供标签或注释,尤其是在需要领域特定知识时。
-
合成数据生成:生成带有已知真实标签的合成数据,以开发和测试机器学习模型。这在没有真实标签数据的情况下尤其有用。
无论是哪种角色,创建、维护并不断评估真实标签数据的质量都是至关重要的,并要注意潜在的偏差和局限性。因为它对数据工程、分析和机器学习工作效果有着重要影响。
时效性
时效性评估数据的捕获、处理和可用的速度。时效性关键绩效指标(KPI)可能包括诸如数据延迟(数据捕获与可用之间的时间差)或遵循数据刷新计划等指标。
测量数据的时效性涉及评估数据在特定时间范围或事件中的新鲜度或有效性。让我们来看一个例子:
-
我们首先导入所需的库:
import pandas as pd import numpy as np from datetime import datetime, timedelta
-
然后我们生成一个包含时间戳和值的随机数据集。时间戳在给定时间范围内随机分布,以模拟真实世界的数据:
np.random.seed(0) # For reproducibility n_samples = 100 start_time = datetime(2023, 10, 25, 9, 0, 0) end_time = datetime(2023, 10, 25, 16, 0, 0) timestamps = [start_time + timedelta(minutes=np.random.randint(0, (end_time - start_time).total_seconds() / 60)) for _ in range(n_samples)] values = np.random.randint(50, 101, n_samples) df = pd.DataFrame({'Timestamp': timestamps, 'Value': values})
-
我们定义一个参考时间戳,用来与数据集的时间戳进行对比:
reference_timestamp = datetime(2023, 10, 25, 12, 0, 0)
-
我们设置了 30 分钟的时效性阈值。时间戳在参考时间戳 30 分钟以内的数据将被视为及时:
timeliness_threshold = 30
-
我们通过计算参考时间戳与每条记录时间戳之间的时间差(以分钟为单位),来计算数据集中每条记录的时效性。我们还创建了一个布尔列,用来指示记录是否符合时效性标准,根据阈值判断:
df['Timeliness'] = (reference_timestamp - df['Timestamp']).dt.total_seconds() / 60 df['Timely'] = df['Timeliness'] <= timeliness_threshold
-
最后,我们计算数据集的平均时效性并显示结果:
average_timeliness = df['Timeliness'].mean()
-
这将显示以下输出:
Dataset with Timestamps: Timestamp Value Timeliness Timely 0 2023-10-25 11:52:00 71 8.0 True 1 2023-10-25 09:47:00 98 133.0 False 2 2023-10-25 10:57:00 99 63.0 False 3 2023-10-25 12:12:00 55 -12.0 True 4 2023-10-25 14:23:00 91 -143.0 True Average Timeliness (in minutes): -23.8 Percentage of Timely Records: 61.0 %
此示例提供了一个更真实的数据集及时性模拟,其中包含随机生成的时间戳和及时性阈值。平均及时性表示数据集相对于 参考时间戳的平均时间偏差。
良好的及时性
低平均及时性和高及时记录的百分比表明数据集当前,并且与参考时间戳很好地对齐。这在实时应用或数据最新性至关重要的场景中是可取的。
这里的一个重要考虑因素是如何定义参考时间戳。参考时间戳是数据集时间戳与之比较的时间点。它代表数据的期望或预期时间。例如:在零售店扫描会员卡时创建记录的时间,参考时间是记录在数据库中登录的时间。因此,我们计算的是从事件实际创建到新条目存储在数据库中所需的时间。
参考阈值越小,应用程序需要越实时。另一方面,参考阈值越大,将数据带入系统所需的时间越长(批量应用)。实时处理和批处理之间的选择取决于应用程序的具体要求:
-
实时处理:当需要即时响应、低延迟以及能够在数据到达时立即采取行动时,选择实时处理是合适的。适用于需要做出时间敏感决策的应用场景。
-
批处理:当低延迟不是严格要求,且可以容忍数据处理中的一些延迟时,选择批处理通常更具成本效益,适合可以安排和自动化的任务。
不同数据角色中及时性定义的变化
及时性是数据质量的一个重要方面,适用于各种角色,从数据工程师到数据分析师和机器学习从业者。以下是每个角色如何在现实世界中利用及时性:
-
数据工程师:
-
数据管道监控:数据工程师可以将及时性作为监控数据管道的关键指标。他们可以设置自动警报或检查,确保数据按时到达,并识别和解决数据摄取中的延迟。
-
数据验证:数据工程师可以将及时性检查作为其数据验证流程的一部分,确保数据在用于下游流程之前满足指定的时间条件。
-
-
数据分析师:
-
实时分析:金融或电子商务等领域的分析师依赖实时数据做出信息化决策。他们需要确保分析的数据是最新的,反映当前的情况。
-
KPI 监控:及时性在监控关键绩效指标中至关重要。分析师使用及时数据来跟踪和评估各种业务指标的表现。
-
-
机器学习从业者:
-
特征工程:及时性在机器学习模型的特征工程中起着重要作用。保持特征尽可能更新对模型的训练和评分有直接影响。
-
模型训练和评估:在实时预测模型中,模型训练和评估依赖于及时数据。从业者必须确保训练数据是当前的,以建立有效的模型或执行实时推断。
-
概念漂移检测:及时性对于检测概念漂移至关重要,概念漂移是指数据内部关系随时间变化的情况。机器学习模型需要适应这些变化,及时的数据监控和检测变化至关重要。
-
这里是及时性的一些实际应用:
-
金融:在金融领域,及时性对股票交易、欺诈检测和风险管理至关重要,及时的数据可以带来更好的决策和降低风险。
-
医疗保健:及时性对于医疗数据至关重要,特别是在患者监测和实时健康数据分析中。
-
电子商务:及时的数据对电子商务公司来说至关重要,可以实时监控销售、客户行为和库存。
-
运输与物流:在供应链管理和物流中,实时跟踪和及时的数据对路线优化和库存管理至关重要。
让我们继续谈一谈一致性。
一致性
一致性衡量数据内部一致性的程度,包括确保数据在整个数据集中遵循建立的规则、标准和格式。具体而言,我们应检查以下内容:
-
相同格式:所有记录或列的数据都应该遵循相同的格式、结构和标准。这种一致性确保数据可以轻松处理和比较。
-
遵守标准:数据应符合预定义的规则、指南、命名约定和参考数据。例如,如果数据集包含产品名称,一致性要求所有产品名称都遵循标准化的命名约定。
-
数据类型和格式:一致性检查包括验证数据类型(例如文本、数字和日期)和数据格式(例如日期格式和数值表示)是否一致。
让我们通过一个例子更好地理解:
-
我们首先导入
pandas
库:import pandas as pd
-
然后我们创建一个包含产品信息的样本数据集,包括产品名称。在这个例子中,我们将检查所有产品名称是否按照命名约定以
PROD
开头:data = { 'ProductID': [1, 2, 3, 4, 5], 'ProductName': ['PROD001', 'PROD002', 'Product003', 'PROD004', 'PROD005'], } df = pd.DataFrame(data)
-
让我们定义预期的前缀:
expected_prefix = "PROD"
-
我们通过确保所有产品名称以
PROD
开头来检查ProductName
列的一致性。不一致的名称将被标记:inconsistent_mask = ~df['ProductName'].str.startswith(expected_prefix) df['Consistency'] = ~inconsistent_mask
-
然后我们计算一致行的百分比:
consistent_percentage = (df['Consistency'].sum() / len(df)) * 100
-
最后,我们展示结果,包括包含完整性检查结果的数据集:
print("Dataset with Consistency Check:") print(df)
以下是最终输出:
Dataset with Consistency Check: ProductID ProductName Consistency 0 1 PROD001 True 1 2 PROD002 True 2 3 Product003 False 3 4 PROD004 True 4 5 PROD005 True Percentage of Consistent Rows: 80.00%
在这个特定的数据集中,五个产品名称中有三个符合命名规范,因此一致性率为 80%。Product003
条目被标记为不一致,因为它没有以PROD
开头
这种类型的完整性检查对于确保数据遵循特定标准或约定非常有用,计算出的百分比提供了一个定量衡量,表示有多少记录符合标准
注意
更高的一致性百分比意味着相应列中的值更加一致和符合标准。如果百分比很低,那么说明数据集中有许多不同的值,只要我们理解列代表的含义并且所有唯一值都有其背后的意义,这并不是一个错误
你是否在想,还可以应用哪些其他的完整性检查?
https://github.com/OpenDocCN/freelearn-ds-pt3-zh/raw/master/docs/py-dt-cln-prep-bst-prac/img/01.jpghttps://github.com/OpenDocCN/freelearn-ds-pt3-zh/raw/master/docs/py-dt-cln-prep-bst-prac/img/02.jpg
表 2.1 – 不同的完整性检查选项
让我们接下来讨论唯一性
唯一性
唯一性衡量数据集中唯一值的存在。它可以帮助识别异常,例如重复的键
代码将输出每一列的有效性结果,指示每一列中的值是否符合定义的有效性规则:
-
我们导入
pandas
库:import pandas as pd
-
然后我们创建一个包含电子邮件地址的示例数据集。我们想检查数据集中的所有电子邮件地址是否唯一:
# Create a sample dataset data = { 'Email': ['john.doe@example.com', 'jane.smith@example.com', 'james.doe@example.com', 'susan.brown@example.com'], } df = pd.DataFrame(data)
-
我们检查
Email
列的唯一性,确保数据集中的电子邮件地址没有重复:# Check uniqueness and create a Boolean mask for duplicated email addresses duplicated_mask = df['Email'].duplicated(keep='first') # Create a new column to indicate uniqueness df['Uniqueness'] = ~duplicated_mask
-
接下来,我们计算唯一性百分比:
unique_percentage = (df['Uniqueness'].sum() / len(df)) * 100
-
最后,我们展示结果,包括包含唯一性检查结果的数据集。以下是输出:
Dataset with Uniqueness Check: Email Uniqueness 0 john.doe@example.com True 1 jane.smith@example.com True 2 james.doe@example.com True 3 susan.brown@example.com True Percentage of Unique Records: 100.00%
这个输出表示数据集中的值都是唯一的
唯一性检查在各个行业和使用案例中都很常见。以下是一些常见的现实场景中唯一性检查的例子:
-
客户编号:在客户数据库中,每位客户应有一个唯一的标识符(客户编号),以防止重复的客户记录
-
产品 SKU:在库存和电子商务数据库中,每个产品应该有一个唯一的 SKU,以便识别和管理产品,避免重复
-
电子邮件地址:电子邮件地址在邮件列表或用户数据库中应该是唯一的,以避免发送重复的邮件或创建多个相同电子邮件地址的账户
-
员工编号:在人力资源数据库中,每位员工通常有一个唯一的员工编号,用以区分员工并有效管理他们的记录
-
车辆识别号码(VIN):在汽车行业中,VIN 是每辆车的唯一标识符,用于追踪其历史和所有权
-
条形码和二维码:在零售和物流行业,条形码和二维码为产品、包裹和物品提供唯一的标识符,用于追踪和库存管理
-
用户名和用户 ID:在在线平台和应用中,用户名和用户 ID 对每个用户都是唯一的,用来区分用户并管理账户。
-
序列号:在制造业中,产品通常会有唯一的序列号,用于识别和跟踪单个物品。
-
交易 ID:在金融系统中,每笔交易都会分配一个唯一的交易 ID,以防止重复并确保正确的记录保存。
当数据集中有非唯一记录时,意味着存在具有相同关键属性(例如,ID、姓名或电子邮件地址)的重复条目或记录。非唯一记录可能会导致数据质量问题,甚至在数据分析和报告时产生错误。要修复数据集中的非唯一记录,你可以使用多种方法,包括去除重复、汇总数据或根据具体数据和需求解决冲突。我们将在后续章节讨论这些策略。
重复数据
重复数据评估数据集中的重复或冗余数据的存在。如果你的数据中有重复记录,意味着同一条信息或记录在数据集中出现多次。
示例——客户数据库
假设你在一个公司工作,公司拥有一个客户数据库,跟踪每个客户的信息,包括他们的联系详情、购买记录和互动信息。
问题——重复的客户记录
你发现数据库中有重复的客户记录。这些重复记录可能是由于数据输入错误、系统问题或其他原因造成的。例如,一个名为 John Smith 的客户有两个独立的记录,联系信息略有不同。一个记录的电子邮件地址是john.smith@email.com
,另一个是jsmith@email.com
。
这通常被认为是不可取的,原因有多个:
-
数据准确性:当你有多个相同信息的副本时,很难确定哪个版本是正确或最新的。这可能导致数据不一致和混乱。
-
存储效率:重复记录会占用不必要的存储空间。尤其在处理大数据集时,这可能导致存储成本增加和数据检索时间延长。
-
数据完整性:重复记录可能会影响数据完整性。在数据关系至关重要的情况下,重复记录可能会破坏数据模型的完整性。
-
高效的数据处理:分析、查询和处理重复较少的数据集会更高效。处理时间更短,结果也更有意义,因为你不需要处理重复信息。
-
数据分析:在进行数据分析或运行统计模型时,重复记录可能会扭曲结果,导致错误的结论。减少重复数据对于准确和有意义的分析至关重要。
-
成本节约:存储和管理重复记录会增加存储基础设施和数据管理的成本。消除重复记录可以带来成本节约。
现在假设我们将同样的问题推广到管理数百万客户的公司。你能想象引入重复记录会有多么昂贵和混乱吗?
尽管在数据集中最小化重复记录通常是一种最佳实践,但在某些特定场景下,接受或允许重复记录可能是一个合理的选择:
场景 | 数据表示 |
---|---|
客户订单历史 | 每一行代表客户的单独订单。允许同一客户 ID 的多行以展示订单历史。 |
服务请求 | 记录代表服务请求,包括同一客户或地点随时间发生的多个请求。允许重复记录以保留详细历史。 |
传感器数据 | 每一行包含传感器读数,可能包括多个相同数据值的条目。允许重复记录以跟踪每次读数。 |
日志记录和审计跟踪 | 日志条目记录事件或操作,有些事件可能生成重复条目。保留重复记录以便进行详细的审计跟踪。 |
用户交互数据 | 记录捕捉用户与网站或应用程序的交互。重复记录可以代表重复的交互,用于分析用户行为。 |
变更历史 | 数据版本或文档变更导致多个记录,包括捕捉历史修订的重复记录。保留重复记录用于版本历史。 |
表 2.2 – 重复记录场景
在这些场景中,允许重复记录是为了实现特定的数据管理或分析目标,例如保留历史数据、记录变更或捕捉详细的用户交互。数据的表示方式与这些目标一致,重复记录是故意保留的,以支持这些用例。
让我们通过一个代码示例来看如何跟踪重复记录。代码将输出数据集中找到的重复记录数量:
-
首先,我们导入
pandas
:import pandas as pd
-
接下来,我们创建一个包含员工信息的示例数据集。我们故意引入重复的员工 ID 来演示如何识别重复记录:
data = { 'EmployeeID': [101, 102, 103, 101, 104, 105, 102], 'FirstName': ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank', 'Bob'], 'LastName': ['Smith', 'Johnson', 'Brown', 'Davis', 'Lee', 'White', 'Johnson'], } df = pd.DataFrame(data)
-
我们将使用 pandas 根据
EmployeeID
列来识别并标记重复记录。duplicated()
函数用于创建布尔掩码,True
表示重复记录:duplicated_mask = df.duplicated(subset='EmployeeID', keep='first')
subset='EmployeeID'
参数指定用于检查重复的列。keep='first'
会将重复记录标记为True
,除了第一次出现的记录。你可以根据需要将此参数更改为last
或False
。 -
然后,我们在 DataFrame 中创建一个新的列
'IsDuplicate'
,用于指示每条记录是否为重复记录:df['IsDuplicate'] = duplicated_mask
-
我们通过将重复记录的数量(在
IsDuplicate
列中标记为True
的记录)除以记录总数,然后乘以 100 来计算重复记录的百分比,并将其表示为百分比:duplicate_percentage = (df['IsDuplicate'].sum() / len(df)) * 100
-
最后,我们显示包含
IsDuplicate
列的数据集,以查看哪些记录是重复的。以下是最终的输出:EmployeeID FirstName LastName IsDuplicate 0 101 Alice Smith False 1 102 Bob Johnson False 2 103 Charlie Brown False 3 101 David Davis True 4 104 Eve Lee False 5 105 Frank White False 6 102 Bob Johnson True Percentage of Duplicate Records: 28.57%
该输出表示数据集中的 28.57%的记录是重复的。
注意
重复记录越少, 越好!
数据集中什么样的重复记录数量被认为是“可接受”或“良好”的标准,可能会根据具体情况和数据管理或分析的目标而有所不同。这个问题没有统一的答案,因为它取决于数据类型、数据集的目的和行业标准等因素。
数据使用
数据使用评估数据在组织内的有效利用程度。数据使用的关键绩效指标(KPI)可以包括数据利用率、数据请求或查询的数量,或者关于数据可用性和质量的用户满意度调查。
场景 – 企业商业智能仪表板
假设一家大型企业依赖数据驱动决策来优化其运营、营销策略和财务表现。该公司有一个集中式的商业智能(BI)仪表板,向不同部门和团队提供各种数据分析和洞察。这个仪表板对于监控公司的业绩并做出明智决策至关重要。
在这种情况下,评估数据使用指标对于优化 BI 仪表板的有效性以及确保它满足组织的数据需求至关重要。以下是我们在代码示例中将要追踪的内容:
-
数据利用率:通过跟踪不同部门和团队的数据利用率,组织可以评估仪表板的访问频率以及其中数据的使用广度。例如,营销部门可能有较高的数据利用率,表明他们在依赖仪表板进行活动绩效分析。此指标有助于识别组织中数据驱动洞察最为关键的领域。
-
数据请求或查询的数量:监控用户发出的数据请求或查询的数量,可以为我们提供关于通过仪表板进行的数据分析量的洞察。较高的数据请求数量可能表明对数据驱动决策的强烈需求。此指标还可以帮助识别使用高峰时段和受欢迎的数据源。
-
用户满意度得分:通过调查收集用户满意度得分,可以衡量 BI 仪表板在多大程度上满足用户的期望。较低的平均用户满意度得分可能表示仪表板的功能或用户体验需要改进。来自用户的反馈可以指导仪表板的改进。
-
组织数据利用率:计算整个组织的总体数据利用率有助于评估仪表板的相关性及其在实现更广泛业务目标中的有效性。这还为衡量数据利用率的改进提供了一个基准。
要计算上个月的数据请求数量,你需要记录应用程序的数据请求及其相关的时间戳。我们来看一个例子:
-
首先,我们导入
random
库:import random
-
接下来,我们创建一个函数来模拟数据使用指标。在这个函数中,我们将组织中的用户数量设置为 500 个用户,但在实际场景中,你需要用组织中实际的用户数量来替代。让我们来看一下下面的函数:
def simulate_data_usage(): num_users = 500 data_utilization_rates = [random.uniform(20, 90) for _ in range(num_users)] data_requests = [random.randint(1, 100) for _ in range(num_users)] organization_data_utilization_rate = sum(data_utilization_rates) / num_users total_data_requests = sum(data_requests) user_satisfaction_scores = [for _ in range(num_users)] avg_user_satisfaction_score = sum(user_satisfaction_scores) / num_users return { "data_utilization_rates": data_utilization_rates, "organization_data_utilization_rate": organization_data_utilization_rate, "data_requests": data_requests, "total_data_requests": total_data_requests, "user_satisfaction_scores": user_satisfaction_scores, "avg_user_satisfaction_score": avg_user_satisfaction_score, }
该函数的主要目标是模拟组织中每个用户的数据利用率。
random.uniform(20, 90)
函数生成一个介于 20 和 90 之间的随机浮动数值。我们对每个用户都进行这种操作,结果是一个数据利用率的列表。同样,我们模拟每个用户所做的数据请求或查询的数量。在这里,我们使用random.randint(1, 100)
为每个用户生成一个 1 到 100 之间的随机整数,表示数据请求的次数。接下来,我们计算两个组织级的指标,第一个是整个组织的平均数据利用率,第二个是所有用户的总数据请求或查询次数。我们使用 1 到 5 的评分来模拟用户满意度分数。每个用户都会得到一个随机的满意度分数。我们基于模拟的满意度分数来计算整个组织的平均用户满意度分数。 -
我们调用
simulate_data_usage()
函数来运行模拟并将结果存储在data_usage_metrics
变量中:data_usage_metrics = simulate_data_usage()
-
最后,我们展示模拟的数据显示指标。输出结果如下:
Organization Data Utilization Rate: 54.83% Total Number of Data Requests or Queries: 25794 Average User Satisfaction Score: 2.93
捕捉不同数据产品的使用情况对于几个原因至关重要,特别是在那些依赖数据进行决策和提升运营效率的组织中:
-
优化资源:通过了解数据产品的使用情况,组织可以有效地分配资源。这包括识别哪些数据源被大量使用,哪些数据源可能未被充分利用。这有助于优化数据存储、处理和基础设施资源。
-
提升数据质量:监控数据使用情况可以突显数据质量问题。例如,如果某些数据产品很少被访问,可能表明这些数据质量较差或已不再相关。捕捉使用情况可以促进数据质量的改进。
-
识别趋势和模式:数据使用模式可以揭示数据如何被消费,以及哪些类型的分析或报告对用户最有价值。这些信息可以为数据产品的开发和改进策略提供依据。
-
成本管理:了解哪些数据产品需求量大有助于管理与数据相关的成本。它使组织能够明智投资资源,避免在维护或存储使用较少的数据上产生不必要的费用。
-
安全和合规性:跟踪数据使用对数据安全和合规性至关重要。组织可以识别未经授权访问或异常使用模式,这可能表明安全漏洞。它还有助于通过展示对数据访问的控制来遵守数据隐私法规。
-
用户满意度:了解数据产品的使用方式及其是否满足用户需求对用户满意度至关重要。它允许组织根据用户要求定制数据产品,从而提供更好的用户体验。
-
容量规划:捕捉使用数据有助于数据基础设施的容量规划。它确保在高峰使用期间有足够的容量处理数据流量,避免性能瓶颈。
-
投资回报率 (ROI) 测量:对于投资于数据产品的组织来说,跟踪使用情况对于衡量投资回报率至关重要。它有助于确定数据收集、处理和呈现所耗费的资源是否因其对决策和业务结果的影响而合理。
接下来,让我们讨论数据合规性。
数据合规性
数据合规性评估数据遵守法规要求、行业标准或内部数据治理政策的程度。合规性 KPI 可能涉及诸如非合规数据记录数量、符合特定法规的数据百分比或数据合规审计结果等指标。在今天的数据驱动和高度监管的业务环境中,数据合规性对几个重要原因尤为关键,如下表所示。
后果/挑战 | 描述 |
---|---|
法律和监管后果 | 不合规可能导致法律诉讼、罚款和处罚 |
声誉损失 | 负面宣传和失去顾客及利益相关者的信任 |
财务影响 | 与罚款、法律费用、数据泄露通知等相关的成本 |
数据泄露 | 增加安全漏洞和未经授权访问的风险 |
数据质量问题 | 不准确或不完整的数据影响决策和效率 |
顾客流失 | 顾客中断与不合规组织的关系 |
法律责任 | 个人和组织可能面临的法律责任 |
额外的监控和监督 | 强化的法规监控和监督 |
难以扩展到国际市场 | 因国际非合规性而阻碍全球扩展 |
表 2.3 – 忽视数据合规性的后果
这里有一个 Python 示例,用于说明一个简化的情景,我们使用随机生成的数据检查数据记录是否符合特定规定的合规性:
-
我们首先导入
random
库:import random
-
接下来,我们创建一个函数来模拟带有合规性检查的数据集,数据记录的数量由给定的值决定:
def simulate_data_compliance(num_records): data_records = [] compliant_count = 0 # Counter for compliant records
-
每条数据记录由诸如
Age
和Consent Given
等属性组成,这些属性是随机生成的:for _ in range(num_records): # Generate a random record (e.g., containing age and consent fields) age = random.randint(18, 100) consent_given = random.choice([True, False])
-
我们根据一个简化的场景定义这些属性的合规性规则,例如,个人必须年满 18 岁或以上才能提供同意:
age_rule = age >= 18 consent_rule = age >= 18 and consent_given
-
我们检查是否符合特定的法规,并且对于每条数据记录,我们报告其是否符合
Age
和Consent
要求:age_compliant = "Age Compliant" if age_rule else "Age Non-Compliant" consent_compliant = "Consent Compliant" if consent_rule else "Consent Non-Compliant" # Define overall compliance status compliance_status = "Compliant" if age_rule and consent_rule else "Non-Compliant"
-
我们引入了一个
compliant_count
变量,用于跟踪符合合规性的记录数量:# Count compliant records if compliance_status == "Compliant": compliant_count += 1 data_records.append({ "Age": age, "Consent Given": consent_given, "Age Compliance": age_compliant, "Consent Compliance": consent_compliant, "Overall Compliance Status": compliance_status })
在生成数据记录的循环内部,每当记录符合定义的规则时,我们就递增
compliant_count
。 -
在生成所有记录后,我们计算符合合规性记录的百分比为
(compliant_count / num_records) * 100
,并将其存储在percentage_compliant
变量中:# Calculate the percentage of compliant records percentage_compliant = (compliant_count / num_records) * 100 return data_records, percentage_compliant
-
我们定义了要模拟的记录数量,并通过调用我们的
simulate_data_compliance
函数开始模拟合规性检查:# Define the number of data records to simulate num_records = 100 # Simulate data compliance checks data_records, percentage_compliant = simulate_data_compliance(num_records)
-
最后,我们显示结果:
# Display the results for a sample of data records and the percentage of compliance sample_size = 10 for record in data_records[:sample_size]: print(record) print(f"\nPercentage of Compliant Records: {percentage_compliant:.2f}%")
这将显示以下输出:
Percentage of Compliant Records: 49.00%
下面是一个总结常见合规性检查及其示例的表格:
合规性检查 | 描述 和示例 |
---|---|
数据隐私合规性 | 确保个人身份信息(PII)的保护;一个例子是安全存储客户姓名和地址 |
GDPR 合规性 | 遵守 GDPR;一个例子是处理用户数据访问和删除请求 |
HIPAA 合规性 | 根据 HIPAA 确保医疗数据保护;一个例子是对电子受保护健康信息(ePHI)的安全处理 |
PCI DSS 合规性 | 遵守 PCI DSS;一个例子是支付处理过程中加密信用卡信息 |
数据保留合规性 | 管理数据保留期限,并确保安全归档或删除 |
同意合规性 | 验证用户对数据收集和处理的明确同意;一个例子是电子邮件营销的选择同意 |
准确性与完整性合规性 | 定期检查和修正数据的准确性与完整性 |
数据分类与处理合规性 | 根据敏感性对数据进行标记并强制访问控制;一个例子是将数据分类为机密并限制访问 |
数据加密合规性 | 对敏感数据进行传输中和静态加密 |
访问控制合规性 | 实施基于角色的访问控制以限制数据访问 |
审计与日志记录合规性 | 维护数据访问和更改的审计日志 |
数据屏蔽与匿名化合规性 | 通过数据屏蔽或匿名化保护敏感数据 |
数据生命周期管理合规性 | 按照政策管理数据从创建到销毁的整个过程 |
数据伦理和道德合规 | 确保数据实践符合伦理标准 |
避免歧视合规性 | 避免数据的歧视性使用;例如,金融服务中的公平贷款实践 |
表 2.4 – 关键合规性检查
实际中,组织可能会选择按日、周、月或季度计算数据质量 KPI,包括完整性。在测量频率和有效评估所需资源之间取得平衡是非常重要的。定期监控和调整计算频率可以帮助确保数据质量根据业务需求持续评估和维护。
如果数据有频繁的更新,数据的监控指标也应当频繁。这确保了数据的任何变化或更新都能及时捕捉,并且质量指标保持最新。
数据越关键,监控指标更新的频率应该越高。这里是关键数据的定义:
特征 | 描述 |
---|---|
对核心运营至关重要 | 对日常组织功能至关重要 |
决策的关键 | 在战略、战术和运营决策中起到关键作用 |
高价值和影响 | 与显著的财务价值和运营影响相关 |
敏感和机密 | 经常包含敏感和机密信息 |
业务连续性和灾难恢复 | 对于连续性规划和恢复措施至关重要 |
客户信任与满意度 | 直接影响信任与满意度 |
竞争优势 | 可能提供竞争优势 |
战略资产 | 被视为战略资源 |
表 2.5 – 关键数据定义
如果用于质量衡量的数据对关键决策过程或敏感操作至关重要,则可能需要更频繁地计算质量 KPI。
现在我们理解了如何根据不同的质量 KPI 评估我们的数据产品,让我们看看在数据生命周期的哪些节点需要应用这些指标。
实施数据生命周期中的质量控制
数据质量应当是数据整个生命周期中的根本考虑。从数据采集到下游分析团队的使用,数据经历了各种变化,确保每个步骤中的质量至关重要。以下是质量检查生命周期的示意图:
图 2.1 – 质量检查生命周期
让我们更深入地了解每个步骤需要发生的内容:
-
数据输入/采集:验证数据源,并确保数据在进入系统时准确、一致地捕获,可以减少下游过程中的错误。
数据角色 --> 数据工程师
-
数据转化:通过在数据转化层中加入质量检查,组织确保数据在从原始来源到最终目的地的整个过程中始终保持可靠、准确和一致。
数据角色 --> 数据工程师
-
数据整合:当从多个来源或系统合并数据时,数据整合可能会引入错误和不一致。此层次的质量检查有助于防止数据质量问题在数据生态系统中传播,并支持对整合数据的高度信任。
数据角色 --> 数据工程师和数据科学家
-
数据消费:分析和机器学习模型在很大程度上依赖于输入数据的质量。在当今以数据为驱动的环境中,这一点尤为重要,因为数据质量直接影响组织的成功与竞争优势。
数据角色 --> 数据科学家,分析师
如前面列表所示,数据在系统中流动。不同的团队合作定义质量指标并应用质量控制。现在,让我们看看如果不同团队之间没有合作,会发生什么。
数据孤岛及其对数据质量的影响
数据孤岛,也称为孤立的数据存储库,在今天的许多组织中普遍存在。数据孤岛是指将数据存储和管理在组织内部孤立或不连接的系统或部门中的做法。这些孤立的数据存储库随着时间的推移发展起来,不同部门或业务单元单独维护数据,导致数据整合变得复杂。组织越来越意识到数据孤岛带来的局限性,认识到它们妨碍了数据驱动的决策和运营效率。因此,打破数据孤岛、推动数据整合和质量提升的努力正在增加,旨在充分挖掘数据资源的潜力。
这些孤岛在我们已经讨论过的维度中给数据质量的维护带来了挑战:
-
不与组织其他部门共享数据会削弱其竞争优势:数据孤岛通过迫使员工花时间从不同的来源寻找数据,拖慢了决策过程,将他们的注意力从获取洞察力和采取行动转移开。通常,数据孤岛与重复性工作相关联,因为各团队独立完成相似任务,缺乏高效的协作和信息共享。不同的数据源之间常常会出现对指标的不同解读,导致团队之间的混淆和争议。假设和视角的不一致阻碍了进展和方向。建立清晰的沟通指南并执行标准化方法是确保对齐期望、促进整个组织理解的关键。
-
不与整个组织共享数据是非常昂贵的:数据孤岛由于维护跨组织的多个分散系统而增加了成本。维护这些不同的系统需要专门的资源,包括人员和基础设施(例如在多个地方的冗余存储)。由于数据存储分散,检索相关信息变得耗时,导致延迟。手动整合来自不同来源的数据会引入潜在错误。
现在,让我们总结一下本章所学的内容。
总结
在本章中,我们讨论了高质量数据的重要性,它为分析、机器学习和明智决策提供了坚实的基础。为了确保数据质量,组织在数据管道的各个阶段实施了一系列检查和措施:
-
数据录入/摄取:数据源会进行验证,以确保数据捕获的准确性和一致性,主要由数据工程师监管。
-
数据转化:质量检查被纳入转化层,以保持数据的可靠性和准确性,通常由数据工程师管理。
-
数据集成:检查可以防止数据质量问题的蔓延,并支持对集成数据的信任,涉及数据工程师和数据科学家。
-
数据消费:高质量的数据输入对于分析和机器学习至关重要,影响用户信任和竞争优势,由数据科学家和分析师推动。
这些质量检查确保数据遵循定义的标准,符合监管要求,并适合其预定用途。通过实施这些检查,组织保持数据的准确性、可靠性和透明度,从而促进更好的决策制定,确保数据驱动的成功。
在下一章,我们将探讨如何使用分析工具持续且自动地监控数据质量。
第三章:数据分析 – 理解数据结构、质量和分布
数据分析指的是对数据集进行细致检查、理解和验证,从中了解其潜在的结构、模式和质量。这是数据管理和数据摄取中的关键步骤,因为它能提高数据质量和准确性,并确保符合监管标准。在本章中,你将学习如何使用不同的工具进行数据分析,并了解如何随着数据量的增加调整策略。
在本章中,我们将深入探讨以下主题:
-
理解数据分析
-
使用 pandas profiler 进行数据分析
-
使用《远大前程》进行数据验证
-
比较《远大前程》和 pandas profiler – 何时使用哪一个
-
如何分析大数据量
技术要求
本章需要安装 Python 解释器,可以通过以下链接下载并按照说明进行安装:www.python.org/downloads/
。
你可以在以下 GitHub 仓库找到本章的所有代码:github.com/PacktPublishing/Python-Data-Cleaning-and-Preparation-Best-Practices/tree/main/chapter03
。
理解数据分析
如果在开始本章之前,你从未听说过 数据分析,它是一个全面的过程,涉及分析和检查来自不同来源的数据,以深入了解数据集的结构、质量和整体特征。让我们从描述数据分析的主要目标开始。
数据分析目标识别
数据分析帮助我们理解数据的结构和质量。因此,我们可以更好地了解如何组织不同的数据集,识别潜在的数据整合问题,评估数据质量,并识别和解决可能影响数据可靠性和可信度的问题。
让我们深入探讨数据分析的三个主要目标。
数据结构
数据分析的主要目标之一是理解数据的结构。这包括检查数据类型、格式和不同数据字段之间的关系。
这里有一个简单的表格结构示例。考虑一个名为 Employee
的表格,存储公司员工的信息:
EmployeeID | FirstName | LastName | Position | Department | Salary |
---|---|---|---|---|---|
1 | John | Doe | 软件工程师 | IT | 75000 |
2 | Jane | Smith | 数据分析师 | 分析 | 60000 |
3 | Bob | Johnson | 项目经理 | 项目管理 | 85000 |
让我们来分析一下这个表格:
-
EmployeeID
: 每个员工的唯一标识符 -
FirstName
和LastName
是存储员工姓名的字段 -
Position
: 员工的职位或职称 -
Department
: 员工所在的部门 -
Salary
:员工的薪资
这个表格结构按行和列进行组织。每一行代表一个特定的员工,每一列代表员工的不同属性或信息。表格结构便于查询、过滤和连接数据。每一列中的值遵循特定的数据类型(例如整数、字符串等),并且可以通过键建立表格之间的关系。
这是一个简化的示例,但在实际应用中,表格可能包含更多列和复杂的关系。
数据质量
数据质量涉及评估数据的整体可靠性和可信度。通过数据分析,我们可以识别出各种数据质量问题,包括重复记录、错误或不一致的值、缺失值和异常值。通过量化这些问题,组织能够了解数据在分析中可以信赖和依赖的程度。
数据分布
理解每个字段或列中的数据分布是数据分析的另一个关键目标。通过分析数据分布,组织可以深入了解数据中的模式、频率和异常。
假设我们为一家电子商务公司工作,收集每天的销售收入数据。通过检查数据分布,我们可以识别出销售趋势:
图 3.1 – 每日销售收入分布
在这个直方图中,我们可以看到销售数据呈正态分布,说明靠近均值的数据比远离均值的数据出现的频率更高。通过这种方式,我们可以了解在正常情况下每天的平均销售额。
现在我们已经了解了数据分析可以解决的挑战,让我们来看看你可以通过哪些不同的方式进行数据分析。
探索性数据分析选项 – 分析工具与手动方法
在进行**探索性数据分析(EDA)**时,你可以采取不同的方法来理解你的数据,包括进行手动分析或使用分析工具。
**手动探索性数据分析(EDA)**涉及编写自定义代码或使用通用数据分析库(例如 Python 中的 pandas)来探索数据。它给予你更多的灵活性和对分析过程的控制。你可以根据具体需求和问题定制分析。手动 EDA 允许更深入的探索,包括自定义计算、特征工程和高级可视化。当处理复杂数据或你拥有特定领域知识时,手动 EDA 会很有帮助。
分析工具是专门用于分析和总结数据的工具或库。它自动化了许多 EDA 任务,并提供数据结构、汇总统计、缺失值、数据类型和分布的快速洞察。它通过自动化重复性任务并提供数据集的全面概览,节省了时间。
让我们更详细地了解何时使用什么:
手动 EDA | 数据分析工具 | |
---|---|---|
优点 | 根据特定需求灵活探索数据 | 自动化流程,快速洞察 |
通过自定义代码深入理解数据 | 跨数据集的一致性和标准化分析 | |
更大控制权的分析技术和可视化 | 自动化的可视化和汇总统计 | |
数据质量问题和异常的识别 | ||
缺点 | 需要大量时间且需人工干预,过程重复 | 生成的报告自定义选项有限 |
更高的人工错误或偏见的可能性 | 可能无法捕捉复杂的关系或模式 | |
分析师或团队之间缺乏标准化 | 与手动分析相比,灵活性较差 | |
手动 EDA | 数据分析工具 | |
依赖预定义的算法和技术 |
表 3.1 – 手动 EDA 与使用分析工具的比较
随着数据量的增加,手动 EDA 变得越来越耗时,并容易出错,导致结果不一致,并可能忽视数据问题。手动方法也缺乏可扩展性和可重复性,处理大型数据集和有效协作变得困难。这就是为什么在本章其余部分,我们将重点介绍如何使用不同的分析工具对数据进行 EDA;但在实践中,通常会采用结合的方法。我们还将提供一些关于如何根据数据量改变工具的见解。
使用 pandas 的 ydata_profiling 进行数据分析
让我们通过一个 Python 示例来展示使用ydata-profiling
库中的ProfileReport
类进行数据分析。
首先,让我们从安装一些库开始:
pip install pandas
pip install ydata-profiling
pip install ipywidgets
在下面的代码示例中,我们将使用seaborn
库中的iris
数据集,它是一个开源数据集。
接下来,我们将读取数据集并使用最少的代码进行初步的 EDA!
-
我们将通过导入库并使用
pandas
的read_csv()
函数直接从 URL 加载数据集来开始:import pandas as pd import ydata_profiling as pp
-
从
seaborn
库加载iris
数据集:iris_data = pd.read_csv('https: //raw. githubusercontent .com/mwaskom/ seaborn-data/master/ iris.csv')
-
接下来,我们将通过使用
pandas_profiling
中的ProfileReport()
函数来执行数据分析:profile = pp.ProfileReport(iris_data)
-
我们将使用
to_file()
方法生成 HTML 报告,将分析结果导出为 HTML 文件,便于分享和进一步分析:profile.to_file("data_profile_report.html")
-
可选地,我们可以将报告嵌入到笔记本中:
profile.to_notebook_iframe()
-
将报告写入 JSON 文件是可选的,但这是一个最佳实践:
profile.to_file(output_path+"/pandas_profiler.json")
让我们逐一探索分析工具的结果。
概览
分析报告中的第一部分是概览部分。在概览部分,你可以看到多个标签,如下图所示:
图 3.2 – pandas 分析器结果概览
在分析器结果的概览标签中,我们可以看到以下内容:
-
变量数量:鸢尾花数据集包含五个变量——花萼长度、花萼宽度、花瓣长度、花瓣宽度和物种
-
观测数:数据集包含 150 行
-
缺失单元格:鸢尾花数据集中没有缺失值
-
重复行:有一行重复数据
然后,我们可以看到警告标签,如下图所示:
图 3.3 – ydata_profiling 分析器的警告标签
在sepal_length
部分:
图 3.4 – 数值特征分析
在sepal_length
部分的分析页面中,我们可以获取更多关于特定数值特征的详细信息。对数据集中的所有其他数值特征也进行了类似的分析。我们可以看到该特征有 35 个不同的值,且数据集中没有缺失值。所有值都是正数,这很合理,因为该特征代表花萼的长度,值的范围应在 4.3 到 7.9 之间。直方图展示了该特征的分布情况。
图 3.5 – 类别特征分析
在species
部分的分析页面中,我们可以获取更多关于特定类别特征的详细信息。对数据集中的所有其他类别特征也进行了类似的分析。我们可以看到该特征有三个不同的值(sectosa
、versicolor
和virginica
),且数据集中没有缺失值。从图表中可以看出,每个特征值的记录数相同(50 条)。
交互作用
分析报告中的另一个部分是交互作用部分,展示了数据集中不同列之间的关系和潜在的交互作用。这些图表特别有助于识别变量之间的潜在相关性或依赖性,通常以散点图的形式呈现。
下图展示了不同变量之间的交互作用。该图表可以针对所有不同的数值变量组合进行创建。我们来看一下花瓣长度与花瓣宽度的示例。
图 3.6 – 花瓣长度与花瓣宽度的交互作用图
在交互图中,我们可以看到一个变量如何影响另一个变量。例如,随着花瓣长度的增加,花瓣宽度也增加。因此,这两者之间存在着线性关系。由于这两个变量之间有强烈的相互作用,因此深入研究这种相互作用并详细检查这一对变量的相关性图表是一个好主意。
相关性
相关矩阵还描绘了变量之间的相互作用,每个单元格表示两个列之间的关系。单元格的颜色根据检测到的相互作用的强度或类型进行编码。这有助于识别两个变量之间的关系强度。正相关通常以一种颜色显示(例如,蓝色),而负相关则以另一种颜色显示(例如,红色),颜色的深浅表示相关性的强度。
例如,花瓣长度和花瓣宽度之间可能存在正相关,表明花瓣长度增加时,花瓣宽度也会增加。
图 3.7 – 数值变量之间的相关性图
从图表中可以看到,蓝色越深,变量之间的相关性越强。花瓣长度和花瓣宽度的正相关性超过 0.75,表明其中一个增加时另一个也会增加。在进行任何建模工作之前,我们需要注意这一点,因为我们可能不需要在数据集中保留这两个变量,因为拥有其中一个就能预测另一个。例如,如果两个变量高度相关,你可以删除其中一个,或者创建一个新特征来包含这两个变量的信息。在某些情况下,移除高度相关的特征可以加快某些机器学习算法的训练时间,因为算法不需要处理冗余信息;此外,简化模型也能让模型更容易理解,减少过拟合的风险。
注意
高相关性阈值:设置高相关性的阈值(例如,0.8 或 0.9)。相关系数高于此阈值的变量被视为高度相关。
缺失值
数据质量的另一个关键方面是缺失值。它指的是数据集中特定条目或变量中缺少数据。缺失值可能由于多种原因出现,例如数据输入错误、传感器故障或数据获取过程中的错误。如果忽视这些缺失值,可能导致偏倚和不准确的结果。
下图显示了数据中每一列非缺失值的百分比:
图 3.8 – 数据中非缺失值的百分比
在当前示例中,我们可以看到数据集中的所有值都是完整的,且所有特征都有 150 个非空值。因此,这对我们来说是个好消息,我们可以继续进行下一步检查。
重复行
数据集中的重复行是指每一列的值都与另一行相同的行。这意味着数据集中的每一列,在重复行中的值与它所重复的行的值完全一致。揭示重复行的存在和范围有助于我们快速识别潜在的数据质量问题。正如我们所说,重复行可能是由于各种原因产生的,例如数据整合问题、错误的去重过程,或只是数据收集过程的性质。
在分析报告中,我们可以在最常见的重复项下看到重复行,其中展示了数据集中重复项的一个示例。
图 3.9 – 数据中的重复行
一般来说,要查找重复行,您需要识别应当唯一的关键列或列的组合。通常,我们会根据数据集中的所有列来识别重复项。如果存在重复项,说明我们有重复的行。我们的示例数据集中只有两行重复数据,如前图所示。
在当前的分析阶段,我们并不处理重复项,因为我们的重点是理解数据的结构和特征。然而,我们需要调查这些重复项的性质和来源。鉴于它们在数据中所占比例很小,我们可以简单地删除每对相同的行中的一行。
示例数据集
抽样是指从较大的数据集中选择一个数据子集的过程,而不是使用整个数据集。在探索性数据分析(EDA)步骤中,我们通常会使用数据的一个样本,因为它可以提供初步的洞见,并帮助在进行全面分析之前提出假设。
图 3.10 – 示例数据集
现在我们已经了解了如何使用 ydata_profiling
库构建数据分析报告,接下来让我们更详细地看看一个非常流行且类似的分析工具——pandas 数据分析工具。
使用 pandas 数据分析工具分析大量数据
Pandas Profiling 是一个强大的库,用于生成数据集的详细报告。然而,对于大数据集来说,分析过程可能会变得耗时且占用大量内存。处理大数据集时,您可能需要考虑一些优化分析过程的策略:
-
抽样:与其对整个数据集进行分析,不如对数据进行随机抽样来生成报告。这可以显著减少计算时间和内存需求,同时仍然提供数据集的代表性概览:
from ydata_profiling import ProfileReport sample_df = iris_data.sample(n=1000) # Adjust the sample size as per your needs report = ProfileReport(sample_df)
-
子集选择:如果你对数据集中的特定列或子集感兴趣,可以仅选择这些列进行分析。这会减少计算负载,并将关注点集中在感兴趣的变量上:
subset_df = iris_data [['sepal_length', 'sepal_width']] # Select columns to profile report = ProfileReport(subset_df)
-
配置分析器选项:pandas profiling 库提供了多个配置选项,允许你精细调整分析过程。你可以调整这些选项,以限制分析的深度、减少计算量,或者跳过某些在分析中不必要的耗时任务:
report = ProfileReport(df, minimal=True) # Generate a minimal report
-
并行处理:如果你的系统支持并行处理,你可以利用它加速分析过程。通过将工作负载分配到多个核心或机器上,你可以可能减少分析大数据集所需的时间:
import multiprocessing with multiprocessing.Pool() as pool: report = pool.map(ProfileReport, [df1, df2, df3]) # Profiling multiple DataFrames in parallel
-
增量分析:如果你的数据集过大,无法完全加载到内存中,可以考虑通过将数据拆分为更小的块并分别进行分析来执行增量分析。然后,你可以将分析结果合并,获得整个数据集的概览:
chunk_size = 10000 chunks = [df[i:i + chunk_size] for i in range(0, len(df), chunk_size)] reports = [ProfileReport(chunk) for chunk in chunks] combined_report = ProfileReport(pd.concat(reports))
注意
这些策略中的一些旨在优化大数据集的分析过程,但与对整个数据集进行分析相比,可能会导致一些粒度和细节的丧失。必须在计算效率和所需的分析深度之间找到平衡。
我们接下来要审查的工具通常用于数据工程密集型的工作流程,因为它提供了大量的灵活性、自动化功能,并且可以与其他工具轻松集成。
使用 Great Expectations 库进行数据验证
Great Expectations 是一个开源的 Python 库,旨在促进数据验证和文档化。它提供了一个框架,用于定义、管理和执行数据质量检查,从而使得在整个数据管道中更容易确保数据的完整性和可靠性。质量检查可以在数据生命周期的不同阶段执行,如下图所示:
图 3.11 – 数据生命周期不同阶段的质量检查
让我们讨论数据生命周期中每个可以应用质量检查的接触点,如前面的图所示:
-
数据输入:在数据输入或数据收集过程中,会进行检查以确保数据的准确捕获和记录。这可能涉及验证数据的格式、范围和类型,以及根据预定义规则或标准进行验证检查。
-
数据转换:如果数据经历了任何转换或变换,如数据清洗或数据标准化,则需要执行质量检查以验证转换后数据的准确性。这有助于确保数据在整个过程中保持完整性。
-
数据集成:在将来自不同来源或系统的数据合并时,必须进行数据质量检查,以识别任何不一致或差异。这可能包括检查重复记录、解决缺失或不匹配的数据,以及调和任何冲突的信息。
-
数据消费:在进行任何数据分析或生成报告之前,必须运行数据质量检查以确保数据的完整性。这包括根据预定义的标准验证数据,检查异常值或不一致,并验证数据集的整体质量。
Great Expectations 允许你为数据设定期望或规则,并在数据生命周期的任何阶段验证数据是否符合这些期望。图 3.12更详细地展示了该库的功能。
图 3.12 – Great Expectations 从数据收集到数据质量结果的流程
如你所见,使用 Great Expectations 时,需要注意三个主要步骤:
-
收集/整理所有你希望应用期望的数据
-
编写期望并将其应用于不同的数据
-
享受干净、高质量和可信数据带来的好处
在下一节中,我们将介绍如何配置 Great Expectations 来验证数据集。
配置 Great Expectations 以适应你的项目
你可以使用 Great Expectations 对照定义的期望来验证数据。该库提供了执行这些验证的功能,并帮助识别数据中的任何不一致或问题。
你需要安装great-expectations
库以进行数据分析。你可以使用以下命令在任何 IDE 或终端中安装该库:
pip install great-expectations==0.18.16
这应该会安装该库。我们将使用与之前相同的数据集,以便展示工具之间的差异:
-
让我们从设置项目开始。打开终端,导航到你希望设置新项目的位置,然后运行以下命令来创建一个新文件夹:
mkdir great_expectations
-
然后,我们将进入新创建的文件夹,输入以下命令:
great_expectations in your project directory where we’ll store all the Expectations we are going to build. The second command will navigate you inside the great_expectations folder we just created.
-
接下来,我们将创建一些文件夹来存储我们的数据和运行示例所需的代码。确保你在
great_expectations
目录下,并运行以下命令:mkdir code mkdir data
你应该已经创建了以下项目结构:
图 3.13 – Great Expectations 项目初始化
-
接下来,我们将运行以下命令来初始化一个新的 Great Expectations 项目。确保你在
great_expectations
文件夹中:great_expectations.yml configuration file, the Expectations and data directories, and other project-specific files. The initialization step is a one-time setup that allows you to define and manage your data Expectations, create validation checkpoints, and generate documentation using Great Expectations. It helps you establish a project-specific configuration and directory structure that enables you to organize your Expectations and maintain consistency across your data pipelines. Once you have initialized the project, you can define Expectations, validate data, and generate reports based on those Expectations using Great Expectations.The preceding code will display the following output:
图 3.14 – Great Expectations 项目初始化
- 当提示时,按 Y,Great Expectations 将继续在
great_expectations
文件夹中为我们构建项目结构。文件夹结构将如下所示:
图 3.15 – Great Expectations 文件夹结构
Great Expectations 的文件夹结构遵循特定的约定,用于组织与数据管道相关的配置、期望和数据文档。让我们来进一步了解一下结构:
-
/uncommitted/
:该目录包含所有未提交的配置和验证文件。在这里,你定义和修改期望、验证以及数据文档。 -
/checkpoints/
:该目录存储检查点文件,这些文件包含一组期望(Expectations),用于与特定数据批次进行验证。检查点对于在数据的特定部分或子集上运行验证非常有用。 -
/expectations/
:该目录存储期望套件(Expectation Suites)和期望文件(Expectation files)。期望套件是相关期望的集合,而期望文件包含单个期望。你可以在此文件夹内创建子目录,以根据数据源或数据资产组织你的期望。 -
/plugins/
:此文件夹用于存储你可能开发的自定义插件和扩展,用以扩展 Great Expectations 的功能。 -
great_expectations.yml
:该配置文件存储 Great Expectations 的部署设置。它包含定义 Great Expectations 如何在你的部署环境中运行的必要信息和参数。
现在我们已经设置并初始化了一个 Great Expectations 项目,接下来让我们使用 Great Expectations 创建我们的第一个数据源。
创建你的第一个 Great Expectations 数据源
到目前为止,我们已经创建了项目结构来构建我们的期望(Expectations)。下一步是获取一些数据来构建期望。为了获取数据集,请访问 github.com/PacktPublishing/Python-Data-Cleaning-and-Preparation-Best-Practices/tree/main/chapter03/great_expectations/code
,获取 1.data_set_up.py
脚本,并将其保存在 great_expectations/code/
文件夹中。现在,让我们通过运行以下 Python 脚本将一些测试数据写入文件夹:great_expectations/code/1.data_set_up.py
。下面是该脚本的样子:
import numpy as np
import pandas as pd
# Load the 'iris' dataset from seaborn library
iris_data = pd.read_csv('https ://raw.githubusercontent .com/mwaskom /seaborn-data /master/iris. csv')
iris_data.to_csv('../data/iris_data.csv', index=False)
print("File written! :)")
在终端中,进入 great_expectations/code/
目录,执行以下命令:
python 1.data_set_up.py
该脚本执行了一个简单的任务:使用 pandas 库从远程源加载 iris
数据集,该数据集位于 seaborn
库的 GitHub 仓库中。然后,它将此数据集保存为 iris_data.csv
文件,保存在 great_expectations/data
目录下。最后,它打印确认信息,表示文件已成功保存。
现在,我们需要告诉 Great Expectations 我们想使用哪些数据来构建 Great Expectations,以及在哪里找到这些数据。在终端中执行以下命令:
great_expectations datasource new
这将显示以下提示:
图 3.16 – Great Expectations 文件配置
请按照终端中的步骤操作,如图 3.16所示,确保选择1
选项,因为我们将处理文件而不是 SQL 数据库。由于我们的数据集足够小,可以放入内存,因此我们可以使用 pandas 进行操作。所以,我们再次选择选项1
。接下来,它会提示您输入数据集文件的路径,由于我们将数据集保存在data
文件夹中,请输入../data
。
完成此步骤后,Great Expectations 会自动为我们创建一个 Jupyter 笔记本以供探索!这个笔记本存储在great_expectations/gx/uncommitted/datasource_new.ipynb
路径下,执行后,如果您不想维护不必要的代码,可以直接删除它。这个笔记本的目的是帮助您创建一个 pandas 数据源配置,避免任何人工错误。
打开笔记本,更新datasource_name
,如以下截图所示,并执行笔记本中的所有单元格。
图 3.17 – Great Expectations – 自定义数据源名称
此时我们可以给它任何名称,但为了与传入的数据保持一致,我们将其命名为iris_data
。从现在开始,当我们提到iris_data
时,我们知道我们正在处理在前一步中创建的iris
数据源的 Expectations。
注意
在 Expectation 验证和数据源之间保持一致和清晰的命名,可以提高可读性,减少错误,并简化维护和调试!
创建您的第一个 Great Expectations 套件
现在我们已经声明了要为其构建 Expectation 的数据源,接下来让我们为iris
数据集构建第一个套件。
打开终端并执行以下命令:
great_expectations suite new
如下图所示,您可以通过多种方式创建 Expectation 套件。
图 3.18 – Great Expectations – 创建您的套件的选项
让我们探讨每个选项:
-
手动操作,不与样本批数据交互(默认)
:这种方法涉及手动定义 Expectations 并配置套件,而不直接与样本批数据交互。Expectations 通常基于您对数据的了解和项目的具体要求。通过指定条件、范围、模式和其他您期望数据满足的标准来定义 Expectations。此方法需要对数据和领域知识有透彻的了解,以定义准确的 Expectations。 -
交互式,使用样本数据批次
: 在这种方法中,你将一个小的代表性数据批次加载到 Great Expectations 中,并使用它交互式地定义期望值。这使你能够直观地检查数据,识别模式,并探索各种数据统计信息。你可以基于对数据的观察和理解,迭代地构建和完善期望值。 -
自动化,通过数据助手
: Great Expectations 提供了一个数据助手功能,该功能根据数据自动建议期望值(Expectations)。数据助手分析数据并生成一组建议的期望值,您可以查看并自定义这些期望值。当你对数据了解有限或希望快速生成期望值的起始点时,这个方法特别有帮助。你可以利用建议的期望值作为基础,并根据自己的领域知识和具体要求进一步优化它们。数据助手通过自动生成初始期望值来加速构建期望值套件的过程。
在这个例子中,我们将使用第三个选项自动构建套件。此功能类似于 pandas profiling 提供的功能,我们之前已经在使用 pandas’ ydata_profiling 进行数据分析部分中探讨过。所以,请继续在终端中选择选项3
,如图 3.19所示。
图 3.19 – Great Expectations – 数据助手选项
下一步,你将被要求选择希望为其创建套件的数据源,这将是上一步的输出。键入1
以选择我们之前构建的iris_data
源,然后输入新期望值套件的名称:expect_iris
。
执行前面的命令后,一个新的笔记本将会自动创建在great_expectations/gx/uncommitted/edit_expect_iris.ipynb
。打开并阅读该笔记本以理解代码的逻辑;总的来说,这个笔记本帮助你从数据中选择你关心的列和其他因素,并让分析器为你创建一些可以稍后调整的期望值(Expectations)。
你可以选择为数据集中的所有列或其中的一部分创建期望值,如图 3.20所示。
图 3.20 – Great Expectations – 套件中包含的列
你可以将所有你不希望创建期望值的列名称添加到exclude_column_name
列表中。对于没有添加到该列表中的任何列,great_expectations
将为你构建期望值。在我们的例子中,我们希望为所有列创建期望值,因此我们将列表留空,如图 3.21所示。
图 3.21 – Great Expectations – 从套件中排除列
记得执行笔记本中的所有单元格,让我们来看看great_expectations
为我们自动构建的所有不同期望。
Great Expectations 套件报告
让我们来看看由great_expectations
创建的分析结果。如图3.22所示,已创建 52 个期望,且都已成功通过。我们可以在概览选项卡中监控成功百分比,以便快速了解每当新的数据流入您的数据管道时,有多少期望通过。
图 3.22 – 报告概览统计
让我们更仔细地看看我们正在验证数据的期望。首先要考虑的是跨表或表级期望,如下图所示:
图 3.23 – 表级期望
这些期望检查数据集中的列是否与给定的列名集匹配,并且数据集是否具有预期的列数。这对于确保传入的数据包含所有预期列非常有用。如果传入的数据未包含期望中的所有列,则该过程将失败。
图 3.24 – 列级期望
下一组期望是为表格中的每一列创建的,我们将其称为特征期望。
图 3.25 – 特征级期望
这些期望会针对每一列分别检查,它们可以包含特征的最小值和最大值、是否接受该列的空值以及其他许多内容。记住,到目前为止,所有的期望都是通过我们使用的工具自动生成的,这些工具并不理解数据的业务上下文。所以,记得根据对数据的业务理解来检查并更新期望,正如我们将在下一部分展示的那样。
手动编辑 Great Expectations
虽然自动生成的期望提供了一个很好的起点,但它们可能不足以满足生产环境下的数据验证需求。在这一阶段,进一步精炼和定制期望套件非常重要。您可以选择手动或交互式编辑期望套件。通常,当您清楚理解预期的数据属性,并希望高效、准确地定义期望时,手动编辑是首选。由于我们已经完成了数据的基本自动分析,因此我们将选择手动编辑方法。
打开终端并执行以下命令:
great_expectations suite edit expect_iris
您将被提示选择如何更新期望套件,可以选择手动或交互式更新。我们将选择手动进行更新。
提供必要的输入后,Great Expectations 会在以下位置打开可用的 Jupyter Notebook:great_expectations/gx/uncommitted/edit_expect_iris.ipynb
。该 Notebook 显示了所有自动生成的 Expectations 的完整列表。这使你能够详细查看和检查 Expectations,清晰地了解 Great Expectations 从数据中推断出的验证规则。查看我们创建的所有 Expectations,并根据需要更新它们。如果你不想使用 Notebook,可以直接打开 great_expectations/gx/expectations/expect_iris.json
文件并在其中更新。
检查点
到目前为止,我们已经建立了与训练数据集的连接,并根据训练数据定义了 Expectations。下一步是将这些 Expectations 应用到新的数据流上,以验证新数据集,并确保其通过检查。因此,我们需要创建 Great Expectation 套件与新数据之间的连接以进行验证。我们可以通过检查点来实现这一点。为此,我们将首先模拟一些测试数据来应用 Expectations。你可以在以下位置找到脚本:github.com/PacktPublishing/Python-Data-Cleaning-and-Preparation-Best-Practices/blob/main/chapter03/great_expectations/code/2.mock_test_dataset.py
。
将其保存在 great_expectations/code/
文件夹中。脚本会自动将测试文件保存到所需的位置,即 great_expectations/data/
。
在终端中,在 great_expectations/code/
目录下,执行以下命令:
python 2.mock_test_dataset.py
让我们仔细看一下我们刚刚执行的代码,从导入语句开始:
import numpy as np
import pandas as pd
从 seaborn
库加载 iris
数据集:
iris_data = pd.read_csv('https: //raw.githubusercontent.com/ mwaskom/seaborn-data /master/iris. csv')
我们将做一些转换,这些转换会导致 Expectations 失败,在这种情况下,我们将把 sepal_length
的值更新为 60
,这将打破我们的 Expectations:
iris_data['sepal_length'] = 60
我们还将重命名列名,以展示列名的更改,并进一步展示数据预期的模式:
iris_data.rename(columns={'petal_width': 'petal_w'}, inplace=True)
我们将编写一个 DataFrame,作为新的数据源来测试我们的 Expectations:
iris_data.to_csv('../data/iris_data_test.csv', index=False)
print("File written! :)")
然后,我们需要创建一个检查点,执行我们在测试数据集上创建的 Great Expectation Suite。要启动检查点,你可以在终端中运行以下命令:
great_expectations checkpoint new expect_iris_ckpnt
执行后,Great Expectations 会自动生成一个 Jupyter Notebook,提供有关检查点的有用信息,位置在:/great_expectations/gx/uncommitted/edit_checkpoint_expect_iris_ckpnt.ipynb
。其中包含有关应用检查点的数据的详细信息。在执行 Notebook 之前,我们需要更新文件名,并指向测试文件,如下所示:
my_checkpoint_name = "expect_iris_ckpnt" # This was populated from your CLI command.
yaml_config = f"""
name: {my_checkpoint_name}
config_version: 1.0
class_name: SimpleCheckpoint
run_name_template: "%Y%m%d-%H%M%S-my-run-name-template"
validations:
- batch_request:
datasource_name: iris_data.csv
data_connector_name: default_inferred_data_connector_name
data_asset_name: iris_data_test.csv
data_connector_query:
index: -1
expectation_suite_name: expect_iris
"""
print(yaml_config)
取消注释最后两行代码,然后执行 Notebook 中的所有单元格:
context.run_checkpoint(checkpoint_name=my_checkpoint_name)
context.open_data_docs()
上述笔记本将把检查点应用于新的数据集,并创建一份报告,列出所有通过或失败的期望。让我们看看结果吧!
图 3.26 – 期望结果
正如预期的那样,我们的期望在列名和花瓣宽度上失败,因为它由于架构变化无法找到正确的列名。
图 3.27 – 由于架构变化导致的期望失败
它还提醒了我们 sepal_length
变量,因为所有值都不符合预期,超出了它所看到的可接受范围!
图 3.28 – 由于超出范围的值导致的期望失败
你能看到它能为我们节省多少问题吗?如果这批数据没有经过检查并直接被导入,后续的处理和集成管道会失败,并且需要大量工作来确定哪个流程失败以及原因。在我们的案例中,我们清楚地知道问题从哪里开始,并且有明确的修复方法。
注意
检查点设计为可重用的,因此你可以在多个数据批次到达时,使用相同的检查点配置来运行。这使得你能够始终如一地验证传入数据是否符合相同的期望集。此外,检查点可以通过各种操作进行增强,例如发送通知、更新数据文档(Data Docs),或根据验证结果触发下游流程。
现在,如果你对 Great Expectations 提供的自动化印象深刻,并希望了解如何将你迄今为止使用 pandas profiling 的所有内容迁移到 Great Expectations Suites 中,那么我们为你准备了相关内容。继续阅读吧。
使用 pandas profiler 构建你的 Great Expectations Suite
pandas profiler 具有一个功能,允许你通过 pandas profiling 过程构建 Expectation Suites。让我们看一下以下示例 great_expectations/code/3.with_pandas_profiler.py
:
import pandas as pd
from ydata_profiling import ProfileReport
# Load the 'iris' dataset from seaborn library
iris_data = pd.read_csv('https: //raw.githubusercontent. com/mwaskom/seaborn-data /master/iris. csv')
# run Pandas Profiling
profile = ProfileReport(iris_data, title="Pandas Profiling Report", explorative=True)
# obtain an Expectation Suite from the profiling
suite = profile.to_expectation_suite(suite_name="my_pandas_profiling_suite")
在这段代码示例中,我们获取了数据并创建了一个 pandas profiling。接着,我们从之前创建的报告中获得了一个 Expectation Suite。我们可以使用这个套件进一步验证并检查另一批数据。
到目前为止,我们已经回顾了不同的分析工具及其工作原理。接下来的步骤是更好地理解何时使用哪种工具以及从哪里开始。
比较 Great Expectations 和 pandas profiler – 何时使用哪个
Pandas profiling 和 Great Expectations 都是数据分析和数据概况分析中有价值的工具,但它们各自有不同的优势和应用场景。以下是对这两种工具的比较。
Pandas Profiler | Great Expectations | |
---|---|---|
数据探索 | 提供快速的洞察和探索性数据总结 | 专注于数据验证和文档编制 |
数据验证 | 限制的数据验证能力 | 高级数据验证,具有明确的期望和规则 |
定制化 | 限制的定制选项 | 提供广泛的定制选项,用于定义期望和规则 |
学习曲线 | 相对容易使用 | 定义期望和配置时具有较陡的学习曲线 |
可扩展性 | 适用于小型到中型数据 | 可扩展至大数据环境,支持分布式处理 |
可视化 | 生成交互式可视化 | 更注重数据验证和文档编制,而非可视化 |
使用案例 | 快速数据探索和初步洞察 | 数据质量控制和强制数据一致性 |
表 3.2 – Great Expectations 与 pandas profiler 比较
Pandas profiling 非常适合快速的数据探索和初步洞察,而 Great Expectations 则在数据验证、文档编制和执行数据质量规则方面表现突出。Pandas profiling 更适合初学者,能提供即时的洞察,而 Great Expectations 则提供更多的定制选项,并且能够扩展到更大的数据集。选择两者之间的工具,取决于项目的具体需求以及所需的数据质量控制级别。
随着数据量的增加,我们需要确保所选择的工具也能够进行扩展。让我们看看如何使用 Great Expectations 实现这一点。
Great Expectations 与大数据
虽然《远大前程》可以有效地用于较小的数据集,但它也提供了机制来解决在大数据环境中扩展数据验证和文档编制的挑战。以下是随着数据量增加,扩展 Great Expectations 的一些注意事项:
-
分布式处理框架:Great Expectations 与流行的分布式处理框架(如 Apache Spark)无缝集成。通过利用这些框架的并行处理能力,Great Expectations 可以将数据验证工作负载分布到集群中,从而实现高效的处理和扩展性。
-
分区和采样:Great Expectations 简化了分区和采样大数据集的过程,并提高了性能和可扩展性。与需要在诸如 pandas profiling 等工具中手动进行分区不同,Great Expectations 自动创建数据子集或分区以供分析和验证。此功能使您能够验证数据的特定子集或分区,而无需一次处理整个数据集。通过自动化分区过程,Great Expectations 简化了分析流程,并消除了手动创建数据块的需求,节省了时间和精力。
-
增量验证:Great Expectations 支持增量验证,而不是每次都重新验证整个大数据集。这意味着当新数据被摄入或处理时,只需要验证相关部分或变化,从而减少整体验证的时间和精力。这是减少检查全部数据所需时间并优化成本的绝佳技巧!
-
缓存和记忆化:Great Expectations 采用缓存和记忆化技术,以优化在重复执行相同验证时的性能。当处理大数据集时,特别有益,因为先前计算的结果可以存储并重复使用,从而最小化冗余计算。
-
基于云的基础设施:利用基于云的基础设施和服务可以提升 Great Expectations 的可扩展性。通过使用云计算平台,如 AWS 或 Azure,你可以动态地扩展资源,以应对增加的数据量和处理需求。
-
高效数据存储:选择适合大数据的优化数据存储技术,如分布式文件系统或列式数据库,可以提升 Great Expectations 的性能和可扩展性。这些技术旨在高效处理大规模数据,并为验证和处理任务提供更快的访问速度。
注意
尽管 Great Expectations 提供了可扩展性选项,但具体的可扩展性措施可能取决于底层基础设施、数据存储系统和你所使用的大数据环境中的分布式处理框架。
总结
本章详细说明了数据分析在确保数据集质量、完整性和可靠性方面的重要性。该过程涉及对数据的深入分析,以了解数据结构、模式和潜在问题。为了进行有效的分析,诸如 pandas profiling 和 Great Expectations 等工具提供了强大的解决方案。Pandas profiling 自动生成综合报告,提供有关数据特征的宝贵见解。而 Great Expectations 则便于创建数据质量预期并允许系统化验证。虽然这些工具在小型数据集上表现出色,但将分析扩展到大数据需要专门的方法。学习数据抽样和并行处理等技巧,有助于在大数据集上进行高效且可扩展的分析。
在下一章中,我们将重点讨论如何清理和处理数据,确保数据格式正确,能够通过预期验证并成功摄入。