讲师中心 微信公众号
AI工具推荐 视频效率加速

Pandas DataFrame中字符串组合的唯一聚合与自定义排序教程

老雪姑娘_3233

老雪姑娘_3233

发布时间:2025-07-17 16:12:21

|

944人浏览过

|

来源于php中文网

原创

Pandas DataFrame中字符串组合的唯一聚合与自定义排序教程

本教程旨在解决Pandas DataFrame中对字符串列进行分组聚合,并对聚合后的唯一成员进行自定义排序的问题。我们将展示如何将多个字符串组合拆分为独立元素,去除重复,并根据预设顺序重新组合。通过利用Python的sorted函数结合自定义映射器,以及itertools.chain的优化方案,实现灵活的数据处理和精确的输出控制。

在数据处理和分析中,我们经常需要对字符串数据进行聚合操作。一个常见的场景是,某一列包含由分隔符连接的多个字符串元素,我们需要按某个键进行分组,然后将这些元素合并,同时去除重复项,并按照特定的顺序排列。

1. 问题描述与初始数据

假设我们有以下Pandas DataFrame,其中CLASS列表示类别,MEMBERS列包含由" & "连接的成员:

import pandas as pd

df = pd.DataFrame({
    'CLASS': ['A', 'B', 'A'],
    'MEMBERS': ['foo & bar', 'bar & luz', 'baz']
})

print(df)
#    CLASS    MEMBERS
# 0      A  foo & bar
# 1      B  bar & luz
# 2      A        baz

我们的目标是:

  1. 按CLASS列进行分组。
  2. 合并每个组中MEMBERS列的所有唯一元素。
  3. 对这些唯一元素进行自定义排序,例如按照['foo', 'bar', 'baz', 'luz']的顺序。

期望的输出结果如下:

# CLASS
# A    foo & bar & baz
# B          bar & luz
# Name: MEMBERS, dtype: object

2. 核心挑战:唯一聚合与自定义排序

首先,我们可以通过groupby()和agg()函数实现初步的唯一聚合。关键在于如何将每个MEMBERS字符串拆分,获取所有独立的成员,然后去重,最后再重新连接。

一个初步的解决方案是:

# 步骤1: 拆分所有成员并去重
# ' & '.join(s) 将一个组内的所有MEMBERS字符串连接成一个长字符串
# .split(' & ') 将这个长字符串拆分成单个成员列表
# set(...) 对列表进行去重
# ' & '.join(...) 将去重后的成员重新连接
aggregated_members = df.groupby('CLASS')['MEMBERS'].agg(
    lambda s: " & ".join(set(' & '.join(s).split(' & ')))
)

print(aggregated_members)
# CLASS
# A    foo & baz & bar
# B          luz & bar
# Name: MEMBERS, dtype: object

可以看到,虽然实现了唯一聚合,但成员的顺序是随机的(因为set是无序的)。接下来,我们需要引入自定义排序逻辑。

361SCAN security check your skill python scripts
361SCAN security check your skill python scripts

扫描并分析已安装技能,用于查看指定技能目录的名称、描述和详情,或列出所有已安装的技能。

下载

3. 解决方案一:利用 sorted() 与自定义键

Python的内置函数sorted()允许我们通过key参数指定一个函数,该函数将应用于列表中的每个元素,并返回一个用于排序的值。我们可以创建一个映射字典,将我们期望的排序顺序编码为整数,然后将其作为key传递给sorted()。

# 定义期望的排序顺序
order = ['foo', 'bar', 'baz', 'luz']

# 创建一个映射字典,将每个成员映射到其在排序列表中的索引
# 例如:{'foo': 0, 'bar': 1, 'baz': 2, 'luz': 3}
mapper = {k: i for i, k in enumerate(order)}

# 应用到DataFrame
result_df = (df.groupby('CLASS')['MEMBERS']
             .agg(lambda s: " & ".join(sorted(set(' & '.join(s).split(' & ')),
                                              key=mapper.get)))
            )

print(result_df)
# CLASS
# A    foo & bar & baz
# B          bar & luz
# Name: MEMBERS, dtype: object

代码解析:

  • order = ['foo', 'bar', 'baz', 'luz']:定义了我们希望的最终排序顺序。
  • mapper = {k: i for i, k in enumerate(order)}:这是一个字典推导式,创建了一个映射器。例如,'foo'映射到0,'bar'映射到1,以此类推。当sorted()函数需要比较两个成员时,它会调用mapper.get(member)来获取对应的整数值,然后根据这些整数值进行排序。
  • set(' & '.join(s).split(' & ')):这部分与之前的逻辑相同,负责将一个组内的所有MEMBERS字符串连接成一个长字符串,然后拆分并去重,得到一个包含所有唯一成员的集合。
  • sorted(..., key=mapper.get):这是核心部分。sorted()函数接收这个唯一成员的集合,并使用mapper.get作为排序键。对于集合中的每个成员,mapper.get()会返回其在order列表中对应的索引。如果某个成员不在mapper中(例如,如果原始数据中出现了order中没有的新成员),mapper.get()默认会返回None,这可能导致排序行为不确定。为了更健壮,可以考虑为mapper.get()提供一个默认值,例如key=lambda x: mapper.get(x, float('inf')),将未知的成员排到最后。
  • " & ".join(...):最后将排序后的成员列表用" & "重新连接成一个字符串。

4. 解决方案二:使用 itertools.chain 优化

当MEMBERS列中的字符串数量非常多,或者每个字符串包含的成员数量很大时,反复调用' & '.join(s).split(' & ')可能会创建大型的中间字符串和列表,效率不高。itertools.chain可以更有效地处理迭代器,避免创建大的中间数据结构。

我们可以定义一个辅助函数来封装聚合和排序逻辑:

from itertools import chain

def custom_join_and_sort(series, order_list):
    """
    对Series中的字符串进行拆分、去重、按指定顺序排序并重新连接。

    Args:
        series (pd.Series): 包含字符串的Series,字符串通过' & '分隔。
        order_list (list): 期望的排序顺序列表。

    Returns:
        str: 排序并连接后的字符串。
    """
    # 创建映射字典
    mapper = {k: i for i, k in enumerate(order_list)}

    # 使用itertools.chain.from_iterable高效地扁平化所有成员
    # x.split(' & ') 将每个字符串拆分成列表
    # chain.from_iterable 将所有这些列表扁平化为一个迭代器
    all_members = chain.from_iterable(x.split(' & ') for x in series)

    # 去重并排序
    # 注意:如果成员不在mapper中,mapper.get(x)将返回None,
    # 可能会导致排序问题。可以考虑添加默认值,如 mapper.get(x, float('inf'))
    # 将未知成员排到最后。
    sorted_unique_members = sorted(set(all_members), key=lambda x: mapper.get(x, float('inf')))

    # 重新连接
    return ' & '.join(sorted_unique_members)

# 应用到DataFrame
result_df_optimized = (df.groupby('CLASS')['MEMBERS']
                       .agg(custom_join_and_sort, order_list=['foo', 'bar', 'baz', 'luz'])
                      )

print(result_df_optimized)
# CLASS
# A    foo & bar & baz
# B          bar & luz
# Name: MEMBERS, dtype: object

代码解析:

  • from itertools import chain:导入itertools.chain模块。
  • chain.from_iterable(x.split(' & ') for x in series):这是优化点。它不再将所有字符串连接成一个巨大的字符串,而是对Series中的每个字符串调用x.split(' & ')生成一个列表,然后chain.from_iterable将这些列表的迭代器“链接”起来,形成一个单一的、扁平化的成员迭代器。这避免了不必要的中间字符串和列表的创建,对于内存和性能有益。
  • key=lambda x: mapper.get(x, float('inf')):这里对mapper.get()增加了默认值float('inf')。这意味着如果order_list中没有包含某个成员,它将被赋予一个非常大的排序值,从而被排到结果字符串的末尾。这增加了代码的健壮性。

5. 注意事项

  • 性能考量:对于非常大的数据集和复杂的字符串操作,itertools.chain通常比' & '.join().split()更高效,因为它处理的是迭代器而不是创建完整的中间列表。
  • 未知成员的处理:在定义mapper和使用sorted(key=...)时,务必考虑如果原始数据中出现order列表中未定义的成员,它们的排序行为。如上所示,使用mapper.get(x, float('inf'))是一个稳健的策略,可以将未知成员排到已知成员之后。
  • 分隔符的一致性:确保MEMBERS列中的分隔符始终一致,本教程中是" & "。如果存在多种分隔符,需要更复杂的解析逻辑。
  • 空值处理:如果MEMBERS列可能包含NaN或其他非字符串值,在split(' & ')之前可能需要添加类型检查或空值处理,例如str(x).split(' & ')或x if isinstance(x, str) else ''。

6. 总结

本教程详细介绍了如何在Pandas DataFrame中实现字符串组合的唯一聚合和自定义排序。我们首先展示了如何通过groupby()和agg()结合set进行基本的去重聚合。接着,通过引入sorted()函数和自定义的key(基于映射字典),解决了自定义排序的问题。最后,为了提高效率和健壮性,我们展示了如何使用itertools.chain优化成员的扁平化处理,并讨论了处理未知成员的策略。这些技术在处理复杂的文本数据聚合场景中非常实用。

热门AI工具

更多
WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

相关专题

更多
Python 时间序列分析与预测
Python 时间序列分析与预测

本专题专注讲解 Python 在时间序列数据处理与预测建模中的实战技巧,涵盖时间索引处理、周期性与趋势分解、平稳性检测、ARIMA/SARIMA 模型构建、预测误差评估,以及基于实际业务场景的时间序列项目实操,帮助学习者掌握从数据预处理到模型预测的完整时序分析能力。

320

2025.12.04

Python 数据清洗与预处理实战
Python 数据清洗与预处理实战

本专题系统讲解 Python 在数据清洗与预处理中的核心技术,包括使用 Pandas 进行缺失值处理、异常值检测、数据格式化、特征工程与数据转换,结合 NumPy 高效处理大规模数据。通过实战案例,帮助学习者掌握 如何处理混乱、不完整数据,为后续数据分析与机器学习模型训练打下坚实基础。

252

2026.01.31

Python数据分析与Pandas高级实战
Python数据分析与Pandas高级实战

本专题围绕 Python 数据分析展开,系统讲解 Pandas 的高级用法,包括数据清洗、透视表、时间序列分析以及多表合并与分组操作。通过实战案例,帮助开发者掌握高效处理与分析数据的方法,提高数据处理效率与分析能力。

551

2026.04.13

css中float用法
css中float用法

css中float属性允许元素脱离文档流并沿其父元素边缘排列,用于创建并排列、对齐文本图像、浮动菜单边栏和重叠元素。想了解更多float的相关内容,可以阅读本专题下面的文章。

6487

2024.04.28

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

744

2025.10.23

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

1738

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2664

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6064

2023.10.24

OpenJDK JVM参数怎么调优
OpenJDK JVM参数怎么调优

Java应用运行缓慢,如何调整JVM参数?本专题介绍OpenJDK JVM性能调优的基本流程,涵盖性能指标确认、运行数据采集、内存配置和垃圾回收分析,帮助你先定位瓶颈,再通过对照测试验证效果,避免直接套用参数而影响应用稳定性。

40

2026.10.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn