0

0

Pandas中基于多条件和时间窗口关联数据的高效方法

碧海醫心

碧海醫心

发布时间:2025-09-02 15:47:14

|

1016人浏览过

|

来源于php中文网

原创

Pandas中基于多条件和时间窗口关联数据的高效方法

本教程探讨如何在Pandas中高效地关联两个数据集,特别是当关联条件涉及多个键和时间窗口时。我们将介绍两种方法:利用pyjanitor库的conditional_join实现高性能多条件连接,以及纯Pandas的解决方案。通过实例代码,详细展示如何将交易数据与特定时间范围内的浏览历史进行匹配,并将结果聚合成列表,以满足复杂的数据分析需求。

在数据分析中,我们经常面临需要将两个数据集基于多个维度进行关联的场景,其中一个关键维度是时间窗口。例如,我们可能需要将用户的交易记录与该交易发生前一定时间范围内的浏览行为进行匹配。传统的pd.merge函数主要用于等值连接,而pd.merge_asof虽然可以处理近似时间匹配,但它通常只匹配最近的一个条目,并且会“消耗”已匹配的条目,这不适用于需要获取时间窗口内所有相关记录的场景。

为了更好地说明问题,我们使用以下两个DataFrame作为示例:一个记录了交易信息(trade),另一个记录了用户的浏览历史(view)。我们的目标是为每笔交易找出其发生前7天内的所有相关浏览记录(基于相同的person和code),并将这些浏览记录的日期和值以列表形式附加到交易数据中。

import pandas as pd
import janitor # 确保已安装:pip install pyjanitor

# 交易数据DataFrame
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]
})

# 浏览历史DataFrame
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]
})

# 将日期列转换为datetime类型,以便进行时间计算和比较
trade['date'] = pd.to_datetime(trade['date'])
view['date'] = pd.to_datetime(view['date'])

1. 使用 janitor.conditional_join 实现高效多条件关联

pyjanitor库提供了一个功能强大的conditional_join函数,它允许我们指定多个非等值连接条件,这在处理时间范围匹配等复杂场景时非常有用,并且通常比纯Pandas的宽泛合并再筛选的方法更高效。

实现步骤:

  1. 创建辅助时间列: 对于每笔交易,计算其发生日期前7天的日期作为时间窗口的起始点。
  2. 执行条件连接: 使用conditional_join函数,指定以下连接条件:
    • trade的start_date小于等于view的view_dates(确保浏览日期在窗口起始点之后或等于)。
    • trade的date大于等于view的view_dates(确保浏览日期在交易日期之前或等于)。
    • trade的person等于view的person。
    • trade的code等于view的code。
  3. 重命名和格式化: 重命名view DataFrame中的日期和值列,并将最终的浏览日期格式化为字符串。
  4. 聚合结果: 使用groupby和agg(list)将每个交易的所有匹配浏览记录聚合成列表。
# 使用janitor.conditional_join进行数据关联
out_janitor = (
    trade
    .assign(start_date=lambda d: d['date'].sub(pd.DateOffset(days=7))) # 步骤1: 计算时间窗口起始点
    .conditional_join(
        view.rename(columns={'date': 'view_dates', 'value': 'view_values'}), # 步骤2: 重命名view列
        ('start_date', 'view_dates', '<='), # 条件1: 浏览日期 >= 交易日期 - 7天
        ('date', 'view_dates', '>='),       # 条件2: 浏览日期 <= 交易日期
        ('person', 'person', '=='),         # 条件3: person相等
        ('code', 'code', '=='),             # 条件4: code相等
        right_columns=['view_dates', 'view_values'] # 保留右侧DataFrame的哪些列
    )
    .drop(columns='start_date') # 步骤3: 删除辅助列
    .assign(view_dates=lambda d: d['view_dates'].dt.strftime('%Y-%m-%d')) # 步骤3: 格式化日期
    .groupby(list(trade.columns), as_index=False).agg(list) # 步骤4: 按原始trade列分组并聚合
)

print("使用janitor.conditional_join的结果:")
print(out_janitor)

优点与注意事项:janitor.conditional_join在内部优化了连接过程,特别是在处理多个非等值条件时,能够避免生成过大的中间DataFrame,从而提高性能。对于大规模数据集和复杂的时间窗口关联,它是更为推荐的选择。

2. 纯 Pandas 解决方案

如果没有pyjanitor库,我们也可以使用纯Pandas实现相同的功能。这种方法通常涉及一个更宽泛的初始合并,然后通过条件筛选来缩小结果范围。

美图AI开放平台
美图AI开放平台

美图推出的AI人脸图像处理平台

下载

实现步骤:

  1. 宽泛合并: 首先,基于person和code这两个等值条件,对trade和view进行合并。这将生成一个包含所有可能组合的中间DataFrame。
  2. 时间窗口筛选: 在合并后的DataFrame上,应用两个时间条件进行筛选:
    • 浏览日期(view_dates)必须小于或等于交易日期(date)。
    • 浏览日期(view_dates)必须大于或等于交易日期减去7天(date - pd.DateOffset(days=7))。
  3. 重命名和格式化: 同样重命名view DataFrame中的日期和值列,并将最终的浏览日期格式化为字符串。
  4. 聚合结果: 使用groupby和agg(list)将每个交易的所有匹配浏览记录聚合成列表。
# 纯Pandas解决方案进行数据关联
out_pandas = (
    trade
    .merge(
        view.rename(columns={'date': 'view_dates', 'value': 'view_values'}), # 步骤1: 重命名view列
        on=['person', 'code'], # 步骤1: 基于person和code进行等值合并
        how='left' # 使用左连接以保留所有交易,即使没有匹配的浏览记录
    )
    .loc[lambda d: (d['date'].gt(d['view_dates'])) & # 步骤2: 浏览日期在交易日期之前
                   (d['date'].sub(pd.DateOffset(days=7)).le(d['view_dates'])) # 步骤2: 浏览日期在窗口起始点之后
         ]
    .assign(view_dates=lambda d: d['view_dates'].dt.strftime('%Y-%m-%d')) # 步骤3: 格式化日期
    .groupby(list(trade.columns), as_index=False).agg(list) # 步骤4: 按原始trade列分组并聚合
)

print("\n纯Pandas解决方案的结果:")
print(out_pandas)

优点与注意事项: 纯Pandas方案的缺点在于,merge操作会首先生成一个包含所有person和code组合的笛卡尔积(如果how='inner'或how='left'),即使这些组合在时间上不匹配。对于大型数据集,这可能导致中间DataFrame非常庞大,占用大量内存并影响性能。因此,这种方法更适用于数据量相对较小或对性能要求不那么严格的场景。

3. 总结

本文详细介绍了两种在Pandas中处理多条件和时间窗口数据关联的方法。

  • janitor.conditional_join 提供了更灵活和高效的解决方案,特别适用于需要处理非等值连接(如时间范围)和避免生成大规模中间结果的场景。它通过优化内部连接逻辑,能够更有效地处理复杂的条件匹配。
  • 纯 Pandas 方案 虽然易于理解和实现,但其性能在大数据集上可能受限于生成中间DataFrame的规模。它通过先进行宽泛合并再筛选的方式实现,可能导致内存消耗较大和计算效率降低。

在实际应用中,建议根据数据集的规模、复杂度和性能要求来选择合适的工具和方法。对于复杂的非等值连接,pyjanitor库是一个值得考虑的强大补充,能够显著提升数据处理的效率和可维护性。

相关专题

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

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

51

2025.12.04

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

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

258

2023.08.03

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

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

208

2023.09.04

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

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

1465

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

619

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

550

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

545

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

164

2025.07.29

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

72

2026.01.16

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 4.6万人学习

PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.4万人学习

Django 教程
Django 教程

共28课时 | 3.2万人学习

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

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