0

0

Pandas与NumPy:高效处理分组内行数据全交叉组合的技巧

心靈之曲

心靈之曲

发布时间:2025-08-24 19:44:21

|

213人浏览过

|

来源于php中文网

原创

Pandas与NumPy:高效处理分组内行数据全交叉组合的技巧

本文探讨了如何在Pandas DataFrame中,针对每个分组内的每一行数据,高效地将其与同组内所有其他行的数据进行交叉组合并扩展为新的列。通过结合Pandas的groupby().apply()和NumPy的数组滚动索引技术,我们能够以高性能的方式实现这种复杂的数据转换,避免了低效的循环和合并操作,适用于需要生成组内两两比较或交互特征的场景。

挑战:分组内行数据的全交叉组合

在数据分析和特征工程中,我们经常会遇到这样的需求:给定一个按某个键(例如raceid)分组的数据集,对于组内的每一条记录,我们希望能够将同组内所有其他记录的特定信息作为新的列添加到当前记录中。例如,在一个赛马数据集中,我们可能希望为每匹马的记录添加同场比赛中所有其他马匹的排名、体重等信息,以便进行更深入的分析或构建复杂的特征。

考虑以下原始数据结构,它代表了一场赛马中的六匹马:

import pandas as pd
import numpy as np

data_orig = {
    'meetingId': [178515] * 6,
    'raceId': [879507] * 6,
    'horseId': [90001, 90002, 90003, 90004, 90005, 90006],
    'position': [1, 2, 3, 4, 5, 6],
    'weight': [51, 52, 53, 54, 55, 56],
}
data_orig_df = pd.DataFrame(data_orig)
print("原始数据:")
print(data_orig_df)

期望的输出是这样的:对于第一行(horseId 90001),它将包含所有六匹马的信息,其中它自己的信息作为 _1 后缀的列,第二匹马的信息作为 _2 后缀的列,依此类推。对于第二行(horseId 90002),它自己的信息作为 _1 后缀的列,而其他马匹的信息则相应地滚动填充。

# 期望输出的简化示例结构(部分列)
# horseId_1  position_1  weight_1  horseId_2  position_2  weight_2 ... horseId_6  position_6  weight_6
# 90001           1        51      90002           2        52 ... 90006           6        56
# 90002           2        52      90003           3        53 ... 90001           1        51
# ...

直接使用循环和pd.merge虽然能够实现,但在处理大型数据集和多个分组时,其性能会非常低下。

核心解决方案:利用NumPy的滚动索引

为了高效地实现这种分组内的行数据全交叉组合,我们可以结合Pandas的groupby().apply()方法和NumPy强大的数组索引能力。关键在于创建一个能够“滚动”或“循环移位”数组内容的索引机制。

1. 定义滚动函数

首先,我们定义一个名为roll的函数,它接收一个DataFrame组(不包含分组键),并对其进行操作。

Delphi 7应用编程150例 全书内容 CHM版
Delphi 7应用编程150例 全书内容 CHM版

Delphi 7应用编程150例 CHM全书内容下载,全书主要通过150个实例,全面、深入地介绍了用Delphi 7开发应用程序的常用方法和技巧,主要讲解了用Delphi 7进行界面效果处理、图像处理、图形与多媒体开发、系统功能控制、文件处理、网络与数据库开发,以及组件应用等内容。这些实例简单实用、典型性强、功能突出,很多实例使用的技术稍加扩展可以解决同类问题。使用本书最好的方法是通过学习掌握实例中的技术或技巧,然后使用这些技术尝试实现更复杂的功能并应用到更多方面。本书主要针对具有一定Delphi基础知识

下载
def roll(g):
    """
    对DataFrame组内的数值进行滚动索引,实现行数据的全交叉组合。

    参数:
        g (pd.DataFrame): 组内数据,不包含分组键。

    返回:
        pd.DataFrame: 经过滚动和扩展后的DataFrame。
    """
    # 将DataFrame转换为NumPy数组,便于高效操作
    a = g.to_numpy()
    num_rows = len(a)

    # 创建一个索引数组,用于生成滚动效果
    # x = [0, 1, 2, ..., num_rows-1]
    x = np.arange(num_rows)

    # 核心:生成滚动索引
    # (x[:,None] + x) 创建一个 num_rows x num_rows 的矩阵,
    # 每一行表示相对于原始行的偏移量。
    # 例如,对于 num_rows=6:
    # [[0, 1, 2, 3, 4, 5],
    #  [1, 2, 3, 4, 5, 6],
    #  [2, 3, 4, 5, 6, 7],
    #  [3, 4, 5, 6, 7, 8],
    #  [4, 5, 6, 7, 8, 9],
    #  [5, 6, 7, 8, 9, 10]]
    #
    # % num_rows 实现循环(滚动)效果
    # 例如,对于 num_rows=6:
    # [[0, 1, 2, 3, 4, 5],
    #  [1, 2, 3, 4, 5, 0],
    #  [2, 3, 4, 5, 0, 1],
    #  [3, 4, 5, 0, 1, 2],
    #  [4, 5, 0, 1, 2, 3],
    #  [5, 0, 1, 2, 3, 4]]
    #
    # .ravel() 将这个二维索引矩阵展平为一维数组,用于对原始数组 `a` 进行索引。
    # 例如,展平后为 [0,1,2,3,4,5, 1,2,3,4,5,0, ...]
    #
    # a[...] 使用展平的索引从原始数组 `a` 中提取数据。
    # 例如,a[0], a[1], ..., a[5], a[1], a[2], ..., a[0], ...
    #
    # .reshape(num_rows, -1) 将结果重新塑形。
    # num_rows 保持原始行数,-1 表示列数自动计算,它会是原始列数 * num_rows。
    rolled_data = a[((x[:,None] + x) % num_rows).ravel()].reshape(num_rows, -1)

    # 生成新的列名
    # 例如,如果原始列是 ['horseId', 'position', 'weight']
    # 那么新列名将是 ['horseId_1', 'position_1', 'weight_1', 
    #                'horseId_2', 'position_2', 'weight_2', ...]
    new_columns = [f'{col}_{i+1}' for i in x for col in g.columns]

    # 将NumPy数组转换回DataFrame,并保留原始索引
    return pd.DataFrame(rolled_data, index=g.index, columns=new_columns)

2. 应用 groupby().apply()

有了 roll 函数,我们就可以将其应用到分组后的DataFrame上。

# 定义分组键
group_cols = ['meetingId', 'raceId']

# 执行分组、应用滚动函数并重置索引
output_df = (data_orig_df.groupby(group_cols)
             .apply(lambda g: roll(g.drop(columns=group_cols))) # 对每个组应用roll函数,注意要先移除分组键
             .reset_index(group_cols) # 将分组键重新添加为普通列
            )

print("\n处理后的数据:")
print(output_df)

结果展示

运行上述代码,将得到以下输出(与期望的 data_new 结构一致,只是列名后缀从字母变为数字,这更具通用性):

处理后的数据:
   meetingId  raceId  horseId_1  position_1  weight_1  horseId_2  position_2  weight_2  horseId_3  position_3  weight_3  horseId_4  position_4  weight_4  horseId_5  position_5  weight_5  horseId_6  position_6  weight_6
0     178515  879507      90001           1        51      90002           2        52      90003           3        53      90004           4        54      90005           5        55      90006           6        56
1     178515  879507      90002           2        52      90003           3        53      90004           4        54      90005           5        55      90006           6        56      90001           1        51
2     178515  879507      90003           3        53      90004           4        54      90005           5        55      90006           6        56      90001           1        51      90002           2        52
3     178515  879507      90004           4        54      90005           5        55      90006           6        56      90001           1        51      90002           2        52      90003           3        53
4     178515  879507      90005           5        55      90006           6        56      90001           1        51      90002           2        52      90003           3        53      90004           4        54
5     178515  879507      90006           6        56      90001           1        51      90002           2        52      90003           3        53      90004           4        54      90005           5        55

注意事项与优化

  1. 性能优势:此方法利用NumPy的矢量化操作,避免了Python层面的显式循环,因此在处理大规模数据集时,其性能远超基于iterrows()和pd.merge()的方案。
  2. 内存消耗:这种数据扩展方式会显著增加DataFrame的列数。如果原始组内元素数量较多,生成的DataFrame会非常宽,可能导致巨大的内存消耗。在实际应用中,需要根据具体需求和系统资源评估其可行性。
  3. 列名约定:生成的列名(如horseId_1, position_2)清晰地表明了数据来源。_1通常表示该行自身的数据,_2表示滚动一位后的数据,以此类推。可以根据实际需求调整roll函数中的列名生成逻辑。
  4. 适用场景
    • 特征工程:创建复杂的交互特征,例如,预测一匹马的表现时,同时考虑同场竞技的其他马匹的属性。
    • 组内比较:在组内进行两两比较分析。
    • 数据重塑:将组内数据从长格式转换为宽格式,但不仅仅是简单的透视,而是带有特定顺序和组合的扩展。
  5. 分组键处理:在apply函数内部,我们通过g.drop(columns=group_cols)将分组键从要进行滚动操作的数据中移除,以避免对这些固定值进行不必要的滚动。reset_index(group_cols)则确保最终结果中保留了这些分组信息。

总结

通过巧妙地结合Pandas的groupby().apply()和NumPy的数组滚动索引技术,我们可以高效且优雅地解决分组内行数据全交叉组合的问题。这种方法不仅提供了强大的数据转换能力,也充分利用了底层库的性能优势,是处理复杂数据重塑和特征工程任务的有效策略。然而,在应用时务必关注其潜在的内存消耗,并根据具体业务需求调整。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

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

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

56

2025.12.04

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

538

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

17

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

25

2026.01.06

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

109

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

16

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

131

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

7

2026.01.26

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.3万人学习

Django 教程
Django 教程

共28课时 | 3.5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号