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

Pandas基于时间范围合并DataFrame的高效策略

风丽同学_2223

风丽同学_2223

发布时间:2025-12-14 19:49:16

|

385人浏览过

|

来源于php中文网

原创

pandas基于时间范围合并dataframe的高效策略

在数据分析和处理中,我们经常会遇到需要根据非精确匹配条件合并(或连接)两个DataFrame的场景。其中一个常见的需求是,将一个DataFrame中的记录与另一个DataFrame中某个时间戳落在特定时间范围内的记录进行关联。传统的迭代方法虽然直观,但在处理大量数据时往往效率低下。本文将介绍一种利用NumPy广播机制实现此类时间范围条件合并的高效策略。

理解问题与传统方法的局限性

假设我们有两个DataFrame:

  • df1 包含 time_1 和 time_2 两列,定义了一个时间区间。
  • df2 包含 time_3 列,表示一个具体的时间点。

我们的目标是,对于 df1 中的每一行,找到 df2 中所有 time_3 值介于 df1 当前行的 time_1 和 time_2 之间的行,并将它们合并起来。这意味着 df1 中的一行可能会与 df2 中的多行匹配,从而在结果DataFrame中重复出现。

以下是使用传统Python循环实现此逻辑的示例:

import pandas as pd
import numpy as np

# 模拟数据
data1 = {
    'time_1': pd.to_datetime(['2023-10-01 04:02:00', '2023-10-01 04:03:00']),
    'time_2': pd.to_datetime(['2023-10-01 08:29:00', '2023-10-01 08:49:00']),
    'dummy_data': [-245.67, -1772.95]
}
df1 = pd.DataFrame(data1)

data2 = {
    'time_3': pd.to_datetime([
        '2023-10-01 06:21:13.238024',
        '2023-10-01 06:47:19.796628',
        '2023-10-01 07:37:06.438740',
        '2023-10-01 08:16:16.995256',
        '2023-10-01 08:33:53.081095'
    ]),
    'dummy_data2': [-131.37, -236.28, 5.92, -134.03, -103.73]
}
df2 = pd.DataFrame(data2)

# 传统循环方法(效率低下)
# indexes = {}
# for i in df1.index:
#     s = df2['time_3'].between(df1.loc[i]['time_1'],
#                               df1.loc[i]['time_2'],
#                               inclusive='left')
#     friends = list(s[s == True].index)
#     indexes[i] = friends

# output_df_slow = pd.DataFrame()
# for key in indexes.keys():
#     for idx in indexes[key]:
#         output_df_slow = pd.concat([df1.loc[[key]],
#                                     df2.loc[[idx]]],
#                                    axis=1, ignore_index=True) # 修改为loc[[key]]和loc[[idx]]以保留DataFrame结构
# print(output_df_slow)

上述循环方法在DataFrame规模较小时尚可接受,但当 df1 和 df2 拥有大量行时,嵌套循环和反复的 loc 操作会导致显著的性能问题,因为它们本质上是逐行处理,无法充分利用Pandas和NumPy底层优化的向量化操作。

高效解决方案:利用NumPy广播机制

NumPy的广播(Broadcasting)机制允许我们对不同形状的数组执行算术运算,其核心思想是自动扩展较小数组以匹配较大数组的形状。在条件合并的场景中,我们可以利用广播一次性比较 df1 中的所有时间范围与 df2 中的所有时间点,从而避免显式循环。

macOS UI 自动化技能包 —— 用 Python 控制你的 Mac
macOS UI 自动化技能包 —— 用 Python 控制你的 Mac

让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限

下载

核心步骤与示例代码

  1. 重置索引(可选但推荐):为了确保在后续 iloc 操作中索引的连续性和准确性,建议在操作前重置两个DataFrame的索引。如果原始索引有特殊含义且不希望丢失,可以在重置前保存。

    df1_reset = df1.reset_index(drop=True)
    df2_reset = df2.reset_index(drop=True)
  2. 准备数据进行广播:将需要比较的时间列转换为NumPy数组。关键在于对 df1 的时间范围列进行整形,使其变为列向量([:, None]),这样在与 df2 的时间点(行向量)进行比较时,NumPy会自动将它们广播成一个 N x M 的矩阵,其中 N 是 df1 的行数,M 是 df2 的行数。

    t1 = df1_reset["time_1"].to_numpy()[:, None] # 转换为列向量
    t2 = df1_reset["time_2"].to_numpy()[:, None] # 转换为列向量
    t3 = df2_reset["time_3"].to_numpy()         # 保持为行向量
  3. 执行广播比较:通过简单的逻辑运算符,我们可以实现时间范围的条件判断。结果将是一个布尔矩阵,指示 df1 的每一行与 df2 的每一行是否满足条件。

    # 广播比较:(t1 < t3) & (t3 < t2)
    # 结果是一个 N x M 的布尔矩阵
    # 假设 time_1 <= time_3 < time_2 (根据问题描述的inclusive='left')
    # 如果需要包含 time_2,则改为 (t1 <= t3) & (t3 <= t2)
    # 这里我们采用 (t1 <= t3) & (t3 < t2) 对应 inclusive='left'
    match_matrix = (t1 <= t3) & (t3 < t2)
  4. 获取匹配的索引对:使用 .nonzero() 方法可以获取布尔矩阵中所有 True 值的坐标。这些坐标将以两个数组的形式返回:第一个数组包含 True 值所在的行索引(对应 df1),第二个数组包含 True 值所在的列索引(对应 df2)。

    x_indices, y_indices = match_matrix.nonzero()
    # x_indices 存储 df1_reset 中匹配的行索引
    # y_indices 存储 df2_reset 中匹配的行索引
  5. 组合结果DataFrame:最后,利用 iloc 根据 x_indices 和 y_indices 从 df1_reset 和 df2_reset 中选择相应的行,并通过 pd.concat 将它们水平拼接起来。

    result_df = pd.concat(
        [
            df1_reset.iloc[x_indices].reset_index(drop=True),
            df2_reset.iloc[y_indices].reset_index(drop=True),
        ],
        axis=1,
    )
    print(result_df)

完整示例代码

import pandas as pd
import numpy as np

# 模拟数据
data1 = {
    'time_1': pd.to_datetime(['2023-10-01 04:02:00', '2023-10-01 04:03:00']),
    'time_2': pd.to_datetime(['2023-10-01 08:29:00', '2023-10-01 08:49:00']),
    'dummy_data': [-245.669907, -1772.948571]
}
df1 = pd.DataFrame(data1)

data2 = {
    'time_3': pd.to_datetime([
        '2023-10-01 06:21:13.238024',
        '2023-10-01 06:47:19.796628',
        '2023-10-01 07:37:06.438740',
        '2023-10-01 08:16:16.995256',
        '2023-10-01 08:33:53.081095'
    ]),
    'dummy_data2': [-131.367901, -236.277444, 5.915493, -134.032433, -103.733212]
}
df2 = pd.DataFrame(data2)

# 确保时间列为 datetime 类型
df1['time_1'] = pd.to_datetime(df1['time_1'])
df1['time_2'] = pd.to_datetime(df1['time_2'])
df2['time_3'] = pd.to_datetime(df2['time_3'])

# 1. 重置索引(确保后续iloc操作的正确性)
df1_reset = df1.reset_index(drop=True)
df2_reset = df2.reset_index(drop=True)

# 2. 准备数据进行NumPy广播
# 将 df1 的时间列转换为列向量 (N, 1)
t1 = df1_reset["time_1"].to_numpy()[:, None]
t2 = df1_reset["time_2"].to_numpy()[:, None]
# 将 df2 的时间列保持为行向量 (1, M)
t3 = df2_reset["time_3"].to_numpy()

# 3. 执行广播比较
# 条件:time_3 介于 time_1 和 time_2 之间 (time_1 <= time_3 < time_2)
match_matrix = (t1 <= t3) & (t3 < t2)

# 4. 获取匹配的索引对
x_indices, y_indices = match_matrix.nonzero()

# 5. 组合结果DataFrame
result_df = pd.concat(
    [
        df1_reset.iloc[x_indices].reset_index(drop=True), # 根据x_indices从df1_reset中选择行
        df2_reset.iloc[y_indices].reset_index(drop=True), # 根据y_indices从df2_reset中选择行
    ],
    axis=1, # 水平拼接
)

print("高效合并结果:")
print(result_df)

输出结果示例

高效合并结果:
             time_1              time_2  dummy_data                 time_3  dummy_data2
0 2023-10-01 04:02:00 2023-10-01 08:29:00  -245.669907 2023-10-01 06:21:13.238024  -131.367901
1 2023-10-01 04:02:00 2023-10-01 08:29:00  -245.669907 2023-10-01 06:47:19.796628  -236.277444
2 2023-10-01 04:02:00 2023-10-01 08:29:00  -245.669907 2023-10-01 07:37:06.438740    5.915493
3 2023-10-01 04:02:00 2023-10-01 08:29:00  -245.669907 2023-10-01 08:16:16.995256  -134.032433
4 2023-10-01 04:03:00 2023-10-01 08:49:00 -1772.948571 2023-10-01 06:21:13.238024  -131.367901
5 2023-10-01 04:03:00 2023-10-01 08:49:00 -1772.948571 2023-10-01 06:47:19.796628  -236.277444
6 2023-10-01 04:03:00 2023-10-01 08:49:00 -1772.948571 2023-10-01 07:37:06.438740    5.915493
7 2023-10-01 04:03:00 2023-10-01 08:49:00 -1772.948571 2023-10-01 08:16:16.995256  -134.032433
8 2023-10-01 04:03:00 2023-10-01 08:49:00 -1772.948571 2023-10-01 08:33:53.081095  -103.733212

优势与注意事项

优势

  • 显著的性能提升:NumPy广播利用了底层的C语言实现,避免了Python循环的开销,尤其在处理大型数据集时,速度比纯Python循环快数倍甚至数十倍。
  • 代码简洁与可读性:相比于复杂的嵌套循环和中间数据结构,广播代码更紧凑,逻辑更清晰。
  • 灵活的条件扩展:如果需要增加更复杂的合并条件(例如,除了时间范围,还需要某个属性匹配或不匹配),可以直接在 match_matrix 的计算中添加额外的布尔条件,而无需大幅修改代码结构。

注意事项

  • 内存消耗:NumPy广播会生成一个 N x M 的布尔矩阵。如果 df1 和 df2 的行数 N 和 M 都非常大,这个矩阵可能会占用大量内存,甚至导致内存溢出。例如,如果 N=10^5 且 M=10^5,则矩阵大小为 10^10 个布尔值,这将是巨大的。在处理超大数据集时,可能需要考虑分块处理或其他更专业的数据库连接技术。
  • 索引处理:在进行 iloc 操作之前,重置索引是一个好的实践,可以避免因原始DataFrame索引不连续或重复而导致的潜在问题。如果原始索引很重要,请在重置前将其保存为新列。
  • 数据类型:确保参与比较的时间列都是Pandas的 datetime 对象或NumPy的 datetime64 类型,以保证比较的正确性。

总结

通过利用NumPy的广播机制,我们可以高效地解决Pandas中基于时间范围的条件合并问题。这种方法不仅显著提升了处理速度,还保持了代码的简洁性和可扩展性。然而,在使用时也需留意其潜在的内存消耗,并根据实际数据规模进行权衡和优化。掌握这种高级的Pandas和NumPy用法,将极大地提高你在时间序列数据处理中的效率。

热门AI工具

更多
UP简历
UP简历 Hot

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

WorkBuddy

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

DeepSeek

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

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

豆包大模型

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

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

相关专题

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

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

340

2025.12.04

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

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

252

2026.01.31

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

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

691

2026.04.13

数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3171

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

554

2025.10.31

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

542

2026.02.12

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

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

6204

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3164

2024.02.23

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

40

2026.10.28

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
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