数据分组还在手忙脚乱?Python groupby一招搞定,效率翻倍!

目录

1、初识groupby:基础用法 🐍

1.1 groupby函数简介

1.2 准备数据与分组

2、按键分组 📊

2.1 使用lambda表达式

2.2 自定义key函数

3、连续元素分组 🔗

3.1 不连续元素处理

3.2 连续性与排序

4、组合其他itertools模块 🔨

4.1 itertools.chain与groupby

4.2 itertools.repeat与分组

5、实战演练:数据分析应用 📈

5.1 数据清洗

5.2 统计分析

6、性能优化:高效使用groupby 🚀

6.1 预排序的重要性

6.2 减少内存消耗技巧

7、小贴士:避免常见陷阱 🛠️

7.1 未排序数据陷阱

7.2 key函数的正确使用

8、总结 🌟



1、初识groupby:基础用法 🐍

1.1 groupby函数简介

itertools.groupby 是 Python 标准库 itertools 模块中的一个强大工具,它能够对可迭代对象中的元素进行分组。不同于数据库查询语言中的 GROUP BY 语句 ,groupby 并不会自动对数据进行排序,因此在使用前通常需要先对数据进行预排序,以保证相同元素连续出现,这样才能正确地进行分组。

示例代码:

from itertools import groupby# 示例数据 ,已经按字母顺序排列
data = ['apple', 'banana', 'cherry', 'apple', 'cherry', 'cherry']# 对数据进行分组
grouped_data = groupby(data)# 打印分组结果
for key, group in grouped_data:print(f"{key}: {list(group)}")

输出:

apple: ['apple', 'apple']
banana: ['banana']
cherry: ['cherry', 'cherry', 'cherry']

1.2 准备数据与分组

在使用 groupby 之前,重要的是确保你的数据已经按照分组键进行了排序。如果不进行排序 ,groupby 可能会将不连续但相同的元素分到不同的组中,导致错误的结果。

示例代码:

# 未排序的数据
unsorted_data = ['banana', 'apple', 'cherry', 'cherry', 'apple', 'cherry']# 先对数据进行排序
sorted_data = sorted(unsorted_data)# 再次使用 groupby
grouped_sorted_data = groupby(sorted_data)# 打印分组结果
for key, group in grouped_sorted_data:print(f"{key}: {list(group)}")

输出:

apple: ['apple', 'apple']
banana: ['banana']
cherry: ['cherry', 'cherry', 'cherry']

通过这个过程,可以看到排序对于 groupby 的正确操作至关重要。在实际应用中 ,可能需要根据具体需求对数据进行更复杂的排序 ,例如按照日期、数值大小等。

2、按键分组 📊

2.1 使用lambda表达式

itertools.groupby 在使用时可以接受一个可选的 key 参数,该参数用于指定分组依据的函数。当未提供 key 函数时,groupby 默认使用元素自身作为分组依据。然而 ,在很多情况下,我们可能需要根据元素的某个属性或计算结果来分组 ,这时就可以利用 key 参数和 lambda 表达式了。

示例代码:

from itertools import groupby# 示例数据,包含了多个字典
data = [{'name': 'Alice', 'age': 25},{'name': 'Bob', 'age': 22},{'name': 'Charlie', 'age': 25},{'name': 'Diana', 'age': 22}
]# 使用 lambda 表达式按年龄分组
grouped_by_age = groupby(sorted(data, key=lambda x: x['age']), key=lambda x: x['age'])# 打印分组结果
for age, group in grouped_by_age:print(f"Age {age}: {[person['name'] for person in group]}")

输出:

Age 22: ['Bob', 'Diana']
Age 25: ['Alice', 'Charlie']

2.2 自定义key函数

除了使用 lambda 表达式 ,我们还可以创建更加复杂的自定义函数作为 key 参数。这允许我们实现更为灵活和具体的分组逻辑 ,比如根据多个字段或复杂条件进行分组。

示例代码:

def custom_key(person):return (person['age'], len(person['name']))# 使用自定义函数按年龄和名字长度分组
grouped_custom = groupby(sorted(data, key=custom_key), key=custom_key)# 打印分组结果
for key, group in grouped_custom:print(f"Key {key}: {[person['name'] for person in group]}")

输出:

Key (22, 3): ['Bob']
Key (22, 5): ['Diana']
Key (25, 5): ['Alice']
Key (25, 7): ['Charlie']

通过使用 key 参数,无论是简单的 lambda 表达式还是自定义函数 ,itertools.groupby 提供了强大的工具来处理和组织数据,使其更加适合进一步的分析和处理。

3、连续元素分组 🔗

3.1 不连续元素处理

在使用 itertools.groupby 时,需要注意的是 ,此函数依赖于元素的连续性。如果相同的关键字值不是连续的,那么它们将被视为不同的组。这意味着 ,如果数据源中的元素未经过排序,groupby 将无法正确地将所有相同关键字值的元素归为一组。

示例代码:

from itertools import groupby# 未排序的数据
data_unsorted = [1, 3, 2, 1, 3, 2, 1]# 直接尝试分组
grouped_unsorted = groupby(data_unsorted)# 打印分组结果
for key, group in grouped_unsorted:print(f"{key}: {list(group)}")

输出:

1: [1]
3: [3]
2: [2]
1: [1]
3: [3]
2: [2]
1: [1]

3.2 连续性与排序

为了确保 groupby 能够正确地识别并分组连续的元素,数据必须首先按照预期的分组关键字进行排序。一旦数据排序完成,groupby 就可以准确地将所有具有相同关键字的连续元素分到同一组中。

示例代码:

# 排序后的数据
data_sorted = sorted(data_unsorted)# 正确排序后使用 groupby
grouped_sorted = groupby(data_sorted)# 打印分组结果
for key, group in grouped_sorted:print(f"{key}: {list(group)}")

输出:

1: [1, 1, 1]
2: [2, 2]
3: [3, 3]

通过对比两个示例的输出,我们可以清楚地看到排序对于 groupby 的重要性。排序确保了相同关键字值的元素是连续的,从而使得 groupby 能够正确地将它们归为一组。在处理复杂数据集时 ,这种连续性的维持是至关重要的 ,因为它直接影响到数据分组的准确性和效率。

4、组合其他itertools模块 🔨

4.1 itertools.chain与groupby

itertools.chain 是一个非常有用的工具,它可以将多个可迭代对象串联成一个单一的序列。当结合 groupby 使用时,chain 可以帮助我们在处理来自不同源的数据时进行统一的分组操作,而无需预先将所有数据合并到一个列表中。

示例代码:

from itertools import chain, groupby# 定义两个数据列表
data1 = ['a', 'b', 'c']
data2 = ['d', 'e', 'f']# 使用 itertools.chain 将两个列表连接起来
combined_data = chain(data1, data2)# 将连接后的数据进行分组
grouped_data = groupby(sorted(combined_data))# 打印分组结果
for key, group in grouped_data:print(f"{key}: {list(group)}")

输出:

a: ['a']
b: ['b']
c: ['c']
d: ['d']
e: ['e']
f: ['f']

4.2 itertools.repeat与分组

itertools.repeat 可以用来无限重复一个元素或指定次数重复一个元素。在某些情况下 ,如果我们想要基于某个固定元素进行分组 ,或者为每个元素添加一个固定的分组标签,repeat 就能派上用场。

示例代码:

from itertools import repeat, groupby# 定义一个数据列表
data = ['a', 'b', 'c']# 使用 itertools.repeat 创建一个无限重复的标签序列
tags = repeat('fruit')# 将数据与标签组合,这里我们假设每个元素都有相同的标签
tagged_data = zip(data, tags)# 将元组展开,只保留第一个元素(即数据),因为标签都是一样的
flattened_data = (element for element, _ in tagged_data)# 将数据进行分组,这里分组实际上是无效的,因为我们使用了 repeat,所有元素都有相同的标签
grouped_tagged_data = groupby(flattened_data)# 打印分组结果
for key, group in grouped_tagged_data:print(f"{key}: {list(group)}")

注意:在第二个示例中 ,由于所有的元素都被赋予了相同的标签,所以实际上 groupby 将会把所有元素视为同一组。如果目标是给每个元素加上标签而不是进行分组,可能需要考虑不同的方法或使用额外的逻辑来处理标签和数据之间的关系。这里展示的主要是 repeat 如何与 groupby 结合使用的一个概念性示例。

5、实战演练:数据分析应用 📈

5.1 数据清洗

在进行数据分析之前,数据清洗是一个必不可少的步骤。itertools.groupby 可以在数据清洗过程中发挥关键作用,特别是当需要去除重复项、标准化数据或对数据进行初步分组时。

示例代码:

from itertools import groupby# 示例数据,包含重复记录
data = [{'id': 1, 'value': 'A'},{'id': 2, 'value': 'B'},{'id': 1, 'value': 'A'},  # 重复记录{'id': 3, 'value': 'C'}
]# 使用 groupby 来去重 ,这里假设每条记录的 'id' 字段是唯一的
unique_data = []
for _, group in groupby(sorted(data, key=lambda x: x['id']), key=lambda x: x['id']):unique_data.append(next(group))# 打印清洗后的数据
print(unique_data)

输出:

[{'id': 1, 'value': 'A'}, {'id': 2, 'value': 'B'}, {'id': 3, 'value': 'C'}]

5.2 统计分析

一旦数据被清洗并准备好,接下来的步骤是对数据进行统计分析。itertools.groupby 在统计分析中同样有其用武之地,尤其当需要对数据进行分组统计时,如计算每个分组的平均值、中位数或频率分布。

示例代码:

# 假设我们有一个包含多个用户购买记录的数据集
purchase_records = [{'user_id': 1, 'amount': 100},{'user_id': 2, 'amount': 150},{'user_id': 1, 'amount': 200},{'user_id': 2, 'amount': 250},{'user_id': 3, 'amount': 300}
]# 使用 groupby 对用户的消费总额进行计算
user_spending = {}
for user_id, records in groupby(sorted(purchase_records, key=lambda x: x['user_id']), key=lambda x: x['user_id']):total_amount = sum(record['amount'] for record in records)user_spending[user_id] = total_amount# 打印每个用户的总消费额
print(user_spending)

输出:

{1: 300, 2: 400, 3: 300}

通过上述示例 ,我们可以看到 itertools.groupby 在数据清洗和统计分析中的实用价值。它不仅能够帮助我们去除数据中的冗余,还能够在数据分析的前期阶段进行有效的数据预处理,从而为后续的深入分析打下坚实的基础。在实际应用中,groupby 结合其他数据处理工具和统计方法,可以构建出强大而灵活的数据分析流程。

6、性能优化:高效使用groupby 🚀

6.1 预排序的重要性

在使用 itertools.groupby 时,数据的预排序是至关重要的。这是因为 groupby 假定相同元素是连续的,只有这样它才能正确地将它们归为同一组。如果没有排序,groupby 将无法正确地识别分组边界,导致错误的分组结果。

示例代码:

from itertools import groupby# 未排序的数据
data = ['apple', 'banana', 'apple', 'cherry', 'banana']# 直接使用 groupby
grouped_unsorted = groupby(data)# 打印分组结果
for key, group in grouped_unsorted:print(f"{key}: {list(group)}")

输出:

apple: ['apple']
banana: ['banana']
apple: ['apple']
cherry: ['cherry']
banana: ['banana']

相比之下,当数据经过排序后,groupby 将能够正确地识别和分组连续的元素。

示例代码:

# 排序后的数据
data_sorted = sorted(data)# 使用 groupby
grouped_sorted = groupby(data_sorted)# 打印分组结果
for key, group in grouped_sorted:print(f"{key}: {list(group)}")

输出:

apple: ['apple', 'apple']
banana: ['banana', 'banana']
cherry: ['cherry']

6.2 减少内存消耗技巧

itertools.groupby 返回的是迭代器,这意味着它在处理数据时不会一次性加载所有数据到内存中。这对于处理大数据集时特别有用 ,因为它可以显著减少内存消耗。然而,当你在遍历 groupby 的结果时将其转换为列表或其他数据结构时,可能会意外地增加内存负担。

为了保持低内存使用 ,应该尽可能直接操作 groupby 返回的迭代器,避免将其结果转换为列表或其他大型数据结构。

示例代码:

# 使用 groupby 迭代器而不转换为列表
for key, group in grouped_sorted:print(f"{key}: {tuple(group)}")  # 使用 tuple 而非 list 来减少内存占用

输出:

apple: ('apple', 'apple')
banana: ('banana', 'banana')
cherry: ('cherry',)

通过直接操作迭代器,而非将其结果存储到内存中,可以有效降低内存消耗 ,特别是在处理大量数据时,这一点尤为重要。这种做法遵循了 Python 中的迭代原则 ,即在可能的情况下 ,优先选择迭代器和生成器,以提高程序的性能和资源利用率。

7、小贴士:避免常见陷阱 🛠️

7.1 未排序数据陷阱

使用 itertools.groupby 时,一个常见的陷阱就是忘记对数据进行排序。groupby 的设计前提是数据中的相同元素是连续的 ,如果数据未排序 ,groupby 可能会将属于同一组的元素错误地分为不同的组。

示例代码:

from itertools import groupby# 未排序的数据
data = [10, 2, 2, 10, 3, 3, 3]# 直接使用 groupby
grouped_unsorted = groupby(data)# 打印分组结果
for key, group in grouped_unsorted:print(f"{key}: {list(group)}")

输出:

10: [10]
2: [2, 2]
10: [10]
3: [3, 3, 3]

可以看出 ,两个 10 被错误地分到了两个不同的组中,这是因为它们在数据中并不是连续的。为了避免这个问题 ,数据在使用 groupby 之前应该进行排序。

示例代码:

# 排序后的数据
data_sorted = sorted(data)# 使用 groupby
grouped_sorted = groupby(data_sorted)# 打印分组结果
for key, group in grouped_sorted:print(f"{key}: {list(group)}")

输出:

2: [2, 2]
3: [3, 3, 3]
10: [10, 10]

7.2 key函数的正确使用

另一个陷阱是在使用 key 函数时的不当选择。key 函数用于决定元素的分组标准 ,但如果选择不当 ,可能导致不符合预期的分组结果。例如,如果 key 函数返回的是不可哈希类型(如列表或字典),则会导致错误。

示例代码:

# 错误的 key 函数使用
data_dicts = [{'id': 1, 'value': 'A'}, {'id': 1, 'value': 'B'}, {'id': 2, 'value': 'C'}]# 使用 lambda 表达式返回字典本身作为 key,这是错误的
grouped_bad_key = groupby(sorted(data_dicts, key=lambda x: x), key=lambda x: x)# 尝试打印分组结果
for key, group in grouped_bad_key:print(f"{key}: {list(group)}")

这段代码会抛出异常,因为字典是不可哈希的,不能作为字典的键或集合的元素,也就不能作为 groupby 的 key 函数的返回值。

正确的key函数使用:

# 使用 id 作为 key 函数的正确使用
grouped_good_key = groupby(sorted(data_dicts, key=lambda x: x['id']), key=lambda x: x['id'])# 打印分组结果
for key, group in grouped_good_key:print(f"{key}: {list(group)}")

输出:

1: [{'id': 1, 'value': 'A'}, {'id': 1, 'value': 'B'}]
2: [{'id': 2, 'value': 'C'}]

通过使用正确的 key 函数,我们能够确保 groupby 正确地根据我们期望的标准进行分组。

8、总结 🌟

探索 itertools.groupby,掌握按键分组与连续元素管理精髓。从基础运用到实战演练,跨越数据清洗至统计分析 ,效能优化贯穿始终。预排序与精选用法揭示避免陷阱之道。本文引领读者深入理解,灵活驾驭数据 ,成就高效处理与洞察力提升之旅。掌握此利器,数据操控自如,分析任务迎刃而解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/377307.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于香橙派 AIpro设计的医院人脸红外测温系统(从0开始开发)

文章目录 一、前言二、主控板介绍三、搭建开发环境3.1 准备需要的配件3.2 开发板实物图3.3 下载开发板资料3.4 下载系统烧写工具3.5 设置开发板启动模式3.6 启动系统3.7 SSH远程登录系统3.8 安装xdrp工具3.9 Window远程登录3.10 取消自动休眠 四、安装Qt开发环境4.1 安装qtcrea…

Ubuntu系统安装mysql之后进行远程连接

1.首先要配置数据库允许进行远程连接 1.1 打开MySQL配置文件 /etc/mysql/mysql.conf.d/mysqld.cnf sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf1.2 修改 bind-address 行 #按i进入插入模式 bind-address 0.0.0.0 #按 Esc 键退出插入模式。 #输入:wq 然后按 Enter 保存并退…

MySQL第八次作业

一、备份与恢复作业: 创库,建表: CREATE DATABASE booksDB; use booksDB; CREATE TABLE books ( bk_id INT NOT NULL PRIMARY KEY, bk_title VARCHAR(50) NOT NULL, copyright YEAR NOT NULL ); CREATE TABLE authors …

在uniapp中如何使用地图

1&#xff0c;技术选择 最好是使用webview html形式加载&#xff0c;避免打包app时的地图加载问题 2&#xff0c;webview使用 使用webview必须按照官方文档,官网地址&#xff1a;https://uniapp.dcloud.net.cn/component/web-view.html <template><view><!…

MATLAB激光通信和-积消息传递算法(Python图形模型算法)模拟调制

&#x1f3af;要点 &#x1f3af;概率论和图论数学形式和图结构 | &#x1f3af;数学形式、图结构和代码验证贝叶斯分类器算法&#xff1a;&#x1f58a;多类型&#xff1a;朴素贝叶斯&#xff0c;求和朴素贝叶斯、高斯朴素贝叶斯、树增强贝叶斯、贝叶斯网络增强贝叶斯和半朴素…

STM32对数码管显示的控制

1、在项目开发过程中会遇到STM32控制的数码管显示应用&#xff0c;这里以四位共阴极数码管显示控制为例讲解&#xff1b;这里采用的控制芯片为STM32F103RCT6。 2、首先要确定数码管的段选的8个引脚连接的单片机的引脚是哪8个&#xff0c;然后确认位选的4个引脚连接的单片机的4…

MVC 生成验证码

在mvc 出现之前 生成验证码思路 在一个html页面上&#xff0c;生成一个验证码&#xff0c;在把这个页面嵌入到需要验证码的页面中。 JS生成验证码 <script type"text/javascript">jQuery(function ($) {/**生成一个随机数**/function randomNum(min, max) {…

登录/注册

目录 1.HTML 2.CSS 3.JS 4.资源 5.运行结果 6.下载链接 7.注意事项 1.HTML <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-sca…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(八)-通过无人机进行无线接入

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…

基于Rspack实现大仓应用构建提效实践|得物技术

一、实践背景 随着项目的逐步迭代&#xff0c;代码量和依赖的逐渐增长&#xff0c;应用的构建速度逐步进入缓慢期。以目前所在团队的业务应用来看&#xff08;使用webpack构建&#xff09;&#xff0c;应用整体构建耗时已经普遍偏高&#xff0c;影响日常开发测试的使用效率&am…

GUI界面开发之tkinter(一)

Tkinter是一个内置的Python库&#xff0c;用于创建图形用户界面&#xff08;GUI&#xff09;。它提供了一组工具和小部件&#xff0c;用于创建窗口、对话框、按钮、菜单和其他GUI元素。 在本篇文章中&#xff0c;主要介绍了窗口等知识点。 大家好&#xff01;我是码银&#x1…

【高中数学/幂函数】比较a=2^0.3,b=3^0.2,c=7^0.1的大小

【问题】 比较a2^0.3,b3^0.2,c7^0.1的大小 【解答】 a2^0.32^3/10(2^3)^1/108^1/10 b3^0.23^2/10(3^2)^1/109^1/10 c7^0.17^1/10 由于yx^1/10在x正半轴是增函数&#xff0c;底数大的得数就大。 因为9>8>7,所以b>a>c 【图像】 在图像上绘出曲线yx^1/10&…

springcolud学习01

创建项目 修改pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…

【游戏引擎之路】登神长阶(七)——x86汇编学习:凡做难事,必有所得

5月20日-6月4日&#xff1a;攻克2D物理引擎。 6月4日-6月13日&#xff1a;攻克《3D数学基础》。 6月13日-6月20日&#xff1a;攻克《3D图形教程》。 6月21日-6月22日&#xff1a;攻克《Raycasting游戏教程》。 6月23日-7月1日&#xff1a;攻克《Windows游戏编程大师技巧》。 7月…

如何指定多块GPU卡进行训练-数据并行

训练代码&#xff1a; train.py import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, Dataset import torch.nn.functional as F# 假设我们有一个简单的文本数据集 class TextDataset(Dataset):def __init__(self, te…

jmeter分布式(四)

一、gui jmeter的gui主要用来调试脚本 1、先gui创建脚本 先做一个脚本 演示&#xff1a;如何做混合场景的脚本&#xff1f; 用211的业务比例 ①启动数据库服务 数据库服务&#xff1a;包括mysql、redis mysql端口默认3306 netstat -lntp | grep 3306处于监听状态&#xf…

【C++】—— 初识C++

【C】—— 初识C 一、什么是 C二、C 的发展历史三、C 版本更新四、C 的重要性五、C 在工作领域中的运用六、C 书籍推荐&#xff1a; 一、什么是 C C语言 是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要…

使用嵌入式知识打造智能手环:nRF52蓝牙开发实战(C++/BLE/传感器)

项目概述 现代人越来越注重健康管理&#xff0c;智能穿戴设备应运而生。本项目旨在利用低功耗蓝牙芯片nRF52832&#xff0c;结合加速度计、心率传感器、陀螺仪等传感器&#xff0c;开发一款功能完善、性能稳定的智能运动手环。该手环能够实时采集用户的运动数据和生理指标&…

vue3 - vue项目自动检测更新

vue3 GitHub Demo 地址 vue3在线预览 vue2 GitHub Demo 地址 vue2 在线预览 web项目当页面检测到需要更新&#xff0c;然后弹框提示是否更新&#xff08;刷新页面&#xff09;这种可以通过纯前端实现也可以通过接口实现 接口实现&#xff1a;通过调用接口轮询和本地的版本号比…

护网HW面试——redis利用方式即复现

参考&#xff1a;https://xz.aliyun.com/t/13071 面试中经常会问到ssrf的打法&#xff0c;讲到ssrf那么就会讲到配合打内网的redis&#xff0c;本篇就介绍redis的打法。 未授权 原理&#xff1a; Redis默认情况下&#xff0c;会绑定在0.0.0.0:6379&#xff0c;如果没有采用相关…