Pandas中基于时间窗口关联和聚合数据的技巧:以交易与浏览记录为例

Pandas中基于时间窗口关联和聚合数据的技巧:以交易与浏览记录为例

本文详细介绍了如何在Pandas中,从两个DataFrame(如交易记录和浏览历史)中,高效地识别并聚合出在特定时间窗口(例如交易前7天)内相关联的数据。教程提供了两种实现方法:一种是利用pyjanitor库的conditional_join函数进行性能优化,另一种是纯Pandas的merge结合条件筛选,并最终通过groupby.agg完成数据聚合,旨在帮助用户处理复杂的时序数据关联需求。

1. 问题描述与数据准备

在数据分析中,我们经常需要根据时间范围将两个数据集关联起来。一个常见的场景是,我们有两个dataframe:一个记录了用户的交易信息,另一个记录了用户的浏览历史。我们的目标是为每笔交易找出其发生前7天内的所有相关浏览记录,并聚合这些记录的日期和值。这里的“相关”意味着交易和浏览记录必须属于同一个用户(person)和同一个商品代码(code)。

考虑以下两个示例DataFrame:

交易记录 (trade)

import pandas as pdimport janitor # 导入 janitor 库trade = pd.DataFrame({'date': ['2019-08-31', '2019-09-01', '2019-09-04'],                      'person': [1, 1,  2],                      'code': [123, 123, 456],                      'value1': [1, 2, 3]})

浏览历史 (view)

view = pd.DataFrame({'date': ['2019-08-29', '2019-08-29', '2019-08-30', '2019-08-31', '2019-09-01',   '2019-09-01', '2019-09-01', '2019-09-02', '2019-09-03'],                      'person': [1, 1, 1, 2, 1, 2, 2, 1, 2],                      'code': [123, 456, 123, 456, 123, 123, 456, 123, 456],                      'value': [1, 2, 3, 4, 5, 6, 7, 8, 9]                    })

在进行时间相关的操作之前,将日期列转换为Pandas的datetime类型是至关重要的。

trade['date'] = pd.to_datetime(trade['date'])view['date'] = pd.to_datetime(view['date'])

我们期望的输出结果是,在原始交易信息的基础上,增加两列:view_dates和view_values,它们分别是以列表形式存储的、在每笔交易前7天内匹配到的浏览记录日期和值。

2. 传统 merge_asof 的局限性

Pandas的merge_asof函数常用于近似合并时序数据。然而,它主要设计用于“最近匹配”场景,通常每个右侧(right)DataFrame的条目最多只能匹配一次。在本例中,我们希望每个交易条目能够匹配到多个浏览历史条目,且这些浏览历史条目可以被不同的交易重复匹配。因此,merge_asof无法直接满足我们的需求。例如,如果使用merge_asof,它可能会将浏览记录[1, 3]分配给第一笔交易,但对于第二笔交易,它可能只会分配[5],而忽略了同样在7天窗口内的[1, 3]。

3. 方法一:使用 pyjanitor.conditional_join (推荐)

pyjanitor库提供了一个强大的conditional_join函数,它允许我们基于多个自定义条件进行DataFrame的连接,包括非等值条件(如时间范围)。这使得它非常适合处理此类复杂的时序数据关联问题,尤其是在处理大规模数据时,其效率通常高于纯Pandas的循环或笛卡尔积合并。

实现步骤

创建辅助列 start_date: 在trade DataFrame中添加一个start_date列,表示每笔交易发生日期前7天的日期。这将作为我们时间窗口的下限。执行 conditional_join: 使用conditional_join函数连接trade和view。时间条件: 确保view_dates在start_date和trade.date之间(即start_date 匹配条件: 确保person和code相等。重命名列: 在view DataFrame中,将date和value列重命名为view_dates和view_values,以避免与trade中的列名冲突,并明确其来源。清理和格式化: 删除不再需要的start_date辅助列,并将view_dates格式化为字符串。聚合结果: 根据原始trade DataFrame的列进行分组,然后将匹配到的view_dates和view_values聚合成列表。

示例代码

# 1. 创建辅助列 'start_date'# 2. 执行 conditional_join# 3. 清理和格式化# 4. 聚合结果out_janitor = (trade  .assign(start_date=lambda d: d['date'].sub(pd.DateOffset(days=7))) # 计算7天前的日期  .conditional_join(view.rename(columns={'date': 'view_dates', 'value': 'view_values'}), # 重命名view列                    ('start_date', 'view_dates', '<='), # 条件1: start_date ='),     # 条件2: trade.date >= view_dates                    ('person', 'person', '=='),       # 条件3: person 匹配                    ('code', 'code', '=='),           # 条件4: code 匹配                    right_columns=['view_dates', 'view_values'] # 保留右侧DataFrame的哪些列                   )  .drop(columns='start_date') # 删除辅助列  .assign(view_dates=lambda d: d['view_dates'].dt.strftime('%Y-%m-%d')) # 格式化日期为字符串  .groupby(list(trade), as_index=False).agg(list) # 按原始trade列分组并聚合列表)print("使用 pyjanitor.conditional_join 的结果:")print(out_janitor)

输出结果

        date  person  code  value1                            view_dates view_values0 2019-08-31       1   123       1              [2019-08-29, 2019-08-30]      [1, 3]1 2019-09-01       1   123       2  [2019-08-29, 2019-08-30, 2019-09-01]   [1, 3, 5]2 2019-09-04       2   456       3  [2019-08-31, 2019-09-01, 2019-09-03]   [4, 7, 9]

4. 方法二:纯 Pandas 解决方案

如果不想引入额外的库,也可以纯粹使用Pandas的merge和条件筛选来实现。这种方法在概念上更直观,但对于非常大的数据集,其性能可能不如pyjanitor.conditional_join,因为它首先会生成一个潜在的较大中间DataFrame(笛卡尔积或近似笛卡尔积)。

实现步骤

进行笛卡尔合并: 首先,基于person和code列对trade和view进行合并。这将为每个交易条目与每个匹配的浏览条目创建一个组合。应用时间条件筛选: 在合并后的DataFrame上,应用两个时间条件:浏览日期必须早于交易日期 (trade_date > view_dates)。浏览日期必须在交易日期前7天之内 (trade_date – 7_days 格式化和聚合: 同样,将view_dates格式化为字符串,然后按原始trade DataFrame的列进行分组,并聚合列表。

示例代码

# 1. 进行笛卡尔合并# 2. 应用时间条件筛选# 3. 格式化和聚合out_pandas = (trade .merge(view.rename(columns={'date': 'view_dates', 'value': 'view_values'}), # 重命名view列并合并        on=['person', 'code']) .loc[lambda d: d['date'].gt(d['view_dates']) & # 筛选条件1: 交易日期 > 浏览日期      d['date'].sub(pd.DateOffset(days=7)).le(d['view_dates']) # 筛选条件2: 交易日期 - 7天 <= 浏览日期     ] .assign(view_dates=lambda d: d['view_dates'].dt.strftime('%Y-%m-%d')) # 格式化日期为字符串 .groupby(list(trade), as_index=False).agg(list) # 按原始trade列分组并聚合列表)print("n使用纯 Pandas 解决方案的结果:")print(out_pandas)

输出结果

        date  person  code  value1                            view_dates view_values0 2019-08-31       1   123       1              [2019-08-29, 2019-08-30]      [1, 3]1 2019-09-01       1   123       2  [2019-08-29, 2019-08-30, 2019-09-01]   [1, 3, 5]2 2019-09-04       2   456       3  [2019-08-31, 2019-09-01, 2019-09-03]   [4, 7, 9]

5. 总结与选择

本教程展示了两种在Pandas中实现基于时间窗口的数据关联和聚合的方法:

pyjanitor.conditional_join: 这种方法在处理复杂的非等值连接(如时间范围)时表现出色,尤其在性能方面优于纯Pandas的笛卡尔合并加筛选,因为它避免了生成过大的中间DataFrame。当处理大型数据集或需要更灵活的连接条件时,强烈推荐使用此方法。纯 Pandas merge + 筛选: 这种方法易于理解和实现,不需要额外库。但在数据量较大时,由于可能产生庞大的中间合并结果,其内存消耗和计算效率可能较低。对于中小型数据集或对性能要求不极致的场景,这是一个可行的选择。

选择哪种方法取决于你的具体需求、数据集大小以及对性能和依赖库的偏好。无论选择哪种,关键都在于正确地定义时间窗口条件并使用groupby.agg(list)来收集所有匹配的条目。

以上就是Pandas中基于时间窗口关联和聚合数据的技巧:以交易与浏览记录为例的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1369643.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月14日 09:50:18
下一篇 2025年12月14日 09:50:32

相关推荐

  • Python 统计 CSV 文件中数字个数的实用指南

    这段代码展示了一种统计 CSV 文件中数字个数的有效方法。它通过逐行读取文件,使用逗号分隔每行,并累加分割后的数字数量,最终输出 CSV 文件中所有数字的总数。 file_path = ‘path_to_your_file.csv’count = 0# 打开文件并逐行读取with open(file…

    好文分享 2025年12月14日
    000
  • Pandas中基于多条件和时间窗口匹配关联数据的策略

    本教程探讨如何在Pandas中高效地将一个DataFrame中的事件与另一个DataFrame中特定时间窗口(例如7天内)内的相关事件进行匹配和聚合。针对merge_asof的局限性,我们将介绍两种主要方法:利用pyjanitor库的conditional_join功能实现多条件高效连接,以及纯Pa…

    2025年12月14日
    000
  • Python统计CSV文件中数字数量的教程

    本文将介绍如何使用Python统计CSV文件中数字的个数。我们将逐行读取CSV文件,使用逗号分隔每行数据,并将分隔后的字符串转换为整数,最后统计数字的总数。通过本文的学习,你将掌握处理CSV文件和统计数据的基本技巧。 统计CSV文件中数字数量的步骤 要统计CSV文件中数字的数量,可以按照以下步骤进行…

    2025年12月14日
    000
  • Transformer模型处理长文本:stride参数的正确应用与实践

    本文深入探讨了在Transformer模型中处理长文本时,如何正确使用stride和truncation等参数,以避免预测中断的问题。我们详细阐述了这些参数在AutoTokenizer.__call__方法和pipeline初始化中的正确配置方式,并提供了具体的代码示例,帮助开发者实现对长文档的无缝…

    2025年12月14日
    000
  • Discord Bot集成指南:通过OAuth2授权将机器人添加到服务器

    本教程详细阐述了将Discord机器人添加到服务器的正确方法。与用户“加入”服务器不同,机器人必须由服务器管理员通过Discord OAuth2授权流程进行添加,而非通过代码主动“加入”邀请链接。文章将指导你构建正确的授权URL,并解释其工作原理及授权后的回调处理。 机器人与服务器的交互机制:核心概…

    2025年12月14日
    000
  • Python CSV文件中的数字元素计数教程

    本教程详细介绍了如何使用Python高效准确地统计CSV文件中独立数字元素的总数。文章通过分步解析文件读取、行内容处理、字符串分割及有效数字过滤等核心步骤,提供了一段优化后的Python代码示例,并讨论了处理空行、空字符串等常见场景的注意事项,旨在帮助用户精确统计CSV数据中的数字。 引言 在数据分…

    2025年12月14日
    000
  • Python统计CSV文件中独立数字个数的高效方法

    本教程详细介绍了如何使用Python准确统计CSV文件中独立数字的个数。针对CSV文件中数字可能分布在单行、多行,并以逗号分隔的复杂情况,文章提供了一种逐行读取、智能分割并过滤无效条目的解决方案,确保统计结果的精确性。 理解CSV数字计数的挑战 在处理csv文件时,我们经常需要统计其中特定类型的数据…

    2025年12月14日
    000
  • 针对SQLModel与SQLite应用的测试策略:使用临时数据库的实践指南

    本教程详细阐述了在测试使用SQLModel和SQLite数据库的CLI应用时,如何有效配置和管理临时数据库。核心内容包括解决sqlite3连接字符串与SQLModel引擎初始化时机不匹配的问题,确保测试环境的隔离性与一致性,并通过代码示例展示如何在pytest中使用tmp_path实现数据库的动态替…

    2025年12月14日
    000
  • 在SQLModel CLI应用中实现SQLite临时数据库测试的策略

    本教程旨在解决使用SQLModel和SQLite开发CLI应用时,在测试环节如何有效利用临时数据库的问题。我们将深入探讨在sqlite3模块和SQLModel中正确配置数据库连接字符串,并重点讲解如何动态地重新配置SQLModel的数据库引擎,以确保测试操作在独立的临时数据库上执行,从而避免测试间的…

    2025年12月14日
    000
  • 使用 PyLaTeX 生成带目录的 PDF 时目录为空的解决方案

    在使用 PyLaTeX 创建包含目录的 PDF 文档时,有时会遇到目录页仅显示 “Contents” 字样,而没有实际的章节和页码信息。这通常是因为 LaTeX 需要进行多次编译才能正确生成目录。第一次编译会提取文档中的章节信息并保存到中间文件中,第二次编译才会读取这些信息并…

    2025年12月14日
    000
  • 使用 PyLaTeX 生成目录时出现空白页的解决方法

    在使用 PyLaTeX 生成包含目录的 PDF 文档时,有时会遇到目录页显示空白,仅显示 “Contents” 标题的情况。这通常是由于 LaTeX 的工作机制导致的,需要进行多次编译才能正确生成目录。 LaTeX 的目录生成机制 LaTeX 在生成目录时,需要经过以下步骤:…

    2025年12月14日
    000
  • 修复 PyLaTeX 生成 PDF 中目录为空的问题

    本文旨在解决使用 PyLaTeX 生成 PDF 文档时目录(Table of Contents)显示为空的常见问题。核心原因在于 LaTeX 编译机制需要多轮处理才能正确生成目录。我们将探讨这一机制,并提供通过安装 latexmk 工具,使 PyLaTeX 自动处理多轮编译的专业解决方案,确保目录内…

    2025年12月14日
    000
  • PyLaTeX生成PDF目录为空问题的解决方案

    本文针对PyLaTeX生成PDF时目录为空的问题提供了解决方案。核心原因在于LaTeX生成目录需要多轮编译,而PyLaTeX的clean_tex=True可能干扰此过程。推荐安装并使用latexmk工具,PyLaTeX能自动检测并利用其进行多轮编译,从而正确生成完整的目录。 问题解析:LaTeX目录…

    2025年12月14日
    000
  • Python asyncio:实现从生成器非阻塞地执行异步任务

    本文探讨了如何在Python中使用asyncio从生成器高效、非阻塞地调度和执行异步任务。核心在于理解asyncio事件循环的运行机制,通过周期性地将控制权交还给事件循环(例如使用await asyncio.sleep(0)),确保已调度的任务能够获得执行机会。文章还介绍了Python 3.11+中…

    2025年12月14日
    000
  • 基于字符偏移的文本解码技术:使用While循环实现动态索引

    本文详细介绍了如何利用Python的while循环和字符的ASCII值实现一种动态索引的文本解码技术。通过定义一个findNext函数来根据当前字符类型计算下一个字符的偏移量,然后在一个主解码函数中循环迭代处理编码文本,逐步构建出原始消息。这种方法避免了使用with open语句,并展示了在不规则文…

    2025年12月14日
    000
  • Playwright 教程:高效处理浏览器新窗口与弹出页

    本教程详细介绍了如何使用 Playwright 捕获并操作浏览器新打开的窗口或弹出页。核心在于利用 page.expect_popup() 上下文管理器,确保在触发弹出事件前做好监听准备,并在弹出后获取其页面对象,进而进行元素定位与交互,确保自动化流程的顺畅执行。 捕获新窗口与弹出页的核心机制 在进…

    2025年12月14日
    000
  • 解决PyTorch CNN训练中批次大小不匹配错误的实用指南

    本文旨在解决PyTorch卷积神经网络(CNN)训练过程中常见的“批次大小不匹配”错误。核心问题通常源于模型架构中全连接层输入尺寸的计算错误以及特征图展平方式不当。通过修正ConvNet模型中全连接层的输入维度、采用动态批次展平方法X.view(X.size(0), -1),并优化损失函数计算lab…

    2025年12月14日
    000
  • PyTorch CNN训练中批次大小不匹配与维度错误:诊断与解决方案

    本文旨在解决PyTorch卷积神经网络(CNN)训练过程中常见的维度不匹配问题,特别是由于模型架构中全连接层输入尺寸计算错误、特征图展平方式不当以及损失函数目标张量形状不符所导致的RuntimeError。文章将详细分析这些问题,并提供经过优化的代码示例与调试技巧,确保模型训练流程的稳定与正确性。 …

    2025年12月14日
    000
  • Playwright自动化测试中如何高效处理新窗口与弹窗

    本文详细讲解了在Playwright自动化测试中如何高效、准确地处理新窗口(Popup)的场景。通过利用page.expect_popup()上下文管理器,可以捕获并控制由用户操作触发的新浏览器窗口。教程将提供具体的代码示例,指导读者如何在新窗口中定位元素、执行操作,并强调了在实际应用中处理弹窗的注…

    2025年12月14日
    000
  • PyTorch CNN训练中的批次大小不匹配错误:深度解析与修复

    本教程详细探讨了PyTorch卷积神经网络(CNN)训练中常见的“批次大小不匹配”错误,并提供了全面的解决方案。我们将重点关注模型架构中的全连接层输入维度计算、数据扁平化策略、损失函数标签处理以及训练与验证循环中的指标统计,旨在帮助开发者构建更健壮、高效的PyTorch模型。在PyTorch中训练深…

    2025年12月14日
    000

发表回复

登录后才能评论
关注微信