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

使用Pandas和NumPy高效合并基于时间范围的数据框

夏宇大大_6402

夏宇大大_6402

发布时间:2025-12-08 20:53:00

|

389人浏览过

|

来源于php中文网

原创

使用pandas和numpy高效合并基于时间范围的数据框

本文详细介绍了如何使用Pandas和NumPy高效合并两个数据框,其中一个数据框的某个时间戳需要落在另一个数据框定义的两个时间列之间。传统迭代方法在大数据量下效率低下,通过引入NumPy广播机制,可以显著提升合并操作的速度和灵活性,同时保持代码简洁,并能轻松扩展以应对更复杂的合并条件,但需注意潜在的内存消耗问题。

基于时间范围的Pandas数据框合并教程

在数据分析中,我们经常需要合并多个数据框。一种常见的复杂场景是,将一个数据框(df2)中的时间戳 (time_3) 与另一个数据框(df1)中定义的时间范围 (time_1 和 time_2) 进行匹配。具体需求是,如果 df2 中的 time_3 落在 df1 中某行的 time_1 和 time_2 之间,则将 df1 的该行与 df2 的对应行合并,并且 df1 的行可能会因多个匹配而重复。

问题描述与传统方法的局限性

假设我们有两个数据框:

  • df1 包含 time_1、time_2 和其他数据列,其中 time_1 和 time_2 定义了一个时间区间。
  • df2 包含 time_3 和其他数据列。

我们的目标是,对于 df1 的每一行,找到所有 df2 中 time_3 落在 df1 当前行 time_1 和 time_2 之间的行,并将它们合并。

一个直观但效率低下的方法是使用嵌套循环。例如,遍历 df1 的每一行,然后对 df2 的所有行进行筛选,找到匹配项后逐个追加到结果数据框。这种方法在数据量较小时尚可接受,但当数据框行数增多时,其 O(n*m) 的时间复杂度会导致性能急剧下降,尤其在Python的循环效率限制下,很容易出现“非常慢”的情况。

采用NumPy广播实现高效合并

为了解决传统迭代方法的效率问题,我们可以利用NumPy的广播(Broadcasting)机制。NumPy广播允许对不同形状的数组执行算术运算,其底层是高度优化的C语言实现,因此在处理大量数据时比Python循环快得多。

1. 准备数据

首先,确保数据框的时间列已正确转换为Pandas的datetime类型。此外,为了后续通过索引进行数据提取,建议重置两个数据框的索引,以确保索引是唯一的且从0开始的整数序列。

python-code-analyz
python-code-analyz

专业Python代码分析与优化,支持语法检查、安全扫描、性能评估、复杂度分析及重构后优化代码生成。

下载
import pandas as pd
import numpy as np

# 示例数据创建
data1 = {
    'time_1': ['2023-10-01 04:02:00', '2023-10-01 04:03:00'],
    'time_2': ['2023-10-01 08:29:00', '2023-10-01 08:49:00'],
    'dummy_data': [-245.66, -1772.94]
}
df1 = pd.DataFrame(data1)
df1['time_1'] = pd.to_datetime(df1['time_1'])
df1['time_2'] = pd.to_datetime(df1['time_2'])

data2 = {
    'time_3': [
        '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.36, -236.27, 5.91, -134.03, -103.73]
}
df2 = pd.DataFrame(data2)
df2['time_3'] = pd.to_datetime(df2['time_3'])

# 重置索引,确保索引是唯一的整数序列
df1 = df1.reset_index(drop=True)
df2 = df2.reset_index(drop=True)

print("df1:\n", df1)
print("\ndf2:\n", df2)

2. 准备NumPy数组进行广播

为了进行广播比较,我们需要将相关的Pandas时间序列转换为NumPy数组。关键在于对 df1 的时间列进行重塑([:, None]),使其成为一个列向量,而 df2 的时间列则保持为行向量。这样,当它们进行比较时,NumPy会自动将它们扩展成一个 n * m 的矩阵(n 是 df1 的行数,m 是 df2 的行数),从而实现“每行对每行”的比较。

# 将时间列转换为NumPy数组
# df1的时间列转换为列向量,df2的时间列转换为行向量
t1 = df1["time_1"].to_numpy()[:, None] # 形状 (n, 1)
t2 = df1["time_2"].to_numpy()[:, None] # 形状 (n, 1)
t3 = df2["time_3"].to_numpy()         # 形状 (m,)

3. 执行广播比较并获取匹配索引

现在,我们可以执行时间范围的比较。t1 < t3 会比较 df1 的每个 time_1 与 df2 的所有 time_3,生成一个 n * m 的布尔矩阵。同理,t3 < t2 也会生成一个 n * m 的布尔矩阵。通过逻辑与 (&) 操作,我们可以得到 time_3 落在 time_1 和 time_2 之间的所有匹配位置。

np.nonzero() 函数会返回这个布尔矩阵中所有 True 值的坐标。x 数组将包含匹配的 df1 行索引,y 数组将包含匹配的 df2 行索引。

# 执行广播比较:t3是否在t1和t2之间
# 结果是一个 n * m 的布尔矩阵
match_matrix = (t1 <= t3) & (t3 <= t2) # 使用 <= 包含边界

# 获取匹配的行索引
# x: df1中匹配行的索引
# y: df2中匹配行的索引
x, y = match_matrix.nonzero()

print("\n匹配的df1索引 (x):", x)
print("匹配的df2索引 (y):", y)

注意:原始问题中使用的 between 函数默认是左闭右开,即 time_1 <= time_3 < time_2。如果需要严格遵循,可以将 t3 < t2 替换为 t3 < t2。本教程为了通用性,使用了 t1 <= t3 和 t3 <= t2,即左右都包含。

4. 合并匹配的行

最后一步是根据 x 和 y 数组中记录的索引来提取 df1 和 df2 中对应的行,并将它们横向合并。df1.iloc[x] 会根据 x 中的索引提取 df1 的行,df2.iloc[y] 同理。pd.concat 函数用于将这两个提取出的子数据框按列(axis=1)合并。

# 根据匹配索引提取并合并数据框行
result = pd.concat(
    [
        df1.iloc[x].reset_index(drop=True), # 提取df1匹配行并重置索引
        df2.iloc[y].reset_index(drop=True), # 提取df2匹配行并重置索引
    ],
    axis=1, # 按列合并
)

print("\n合并结果:\n", result)

完整代码示例

import pandas as pd
import numpy as np

# 1. 示例数据创建
data1 = {
    'time_1': ['2023-10-01 04:02:00', '2023-10-01 04:03:00'],
    'time_2': ['2023-10-01 08:29:00', '2023-10-01 08:49:00'],
    'dummy_data': [-245.66, -1772.94]
}
df1 = pd.DataFrame(data1)
df1['time_1'] = pd.to_datetime(df1['time_1'])
df1['time_2'] = pd.to_datetime(df1['time_2'])

data2 = {
    'time_3': [
        '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.36, -236.27, 5.91, -134.03, -103.73]
}
df2 = pd.DataFrame(data2)
df2['time_3'] = pd.to_datetime(df2['time_3'])

# 2. 重置索引(如果原始索引不保证唯一或连续)
df1 = df1.reset_index(drop=True)
df2 = df2.reset_index(drop=True)

# 3. 准备NumPy数组进行广播
t1 = df1["time_1"].to_numpy()[:, None] # df1的time_1作为列向量
t2 = df1["time_2"].to_numpy()[:, None] # df1的time_2作为列向量
t3 = df2["time_3"].to_numpy()         # df2的time_3作为行向量

# 4. 执行广播比较
# 这里使用 <= 来包含边界,如果需要严格小于,请调整
match_matrix = (t1 <= t3) & (t3 <= t2)

# 5. 获取匹配的df1和df2的行索引
x, y = match_matrix.nonzero()

# 6. 根据匹配索引合并数据框行
result = pd.concat(
    [
        df1.iloc[x].reset_index(drop=True),
        df2.iloc[y].reset_index(drop=True),
    ],
    axis=1,
)

print("\n最终合并结果:\n", result)

注意事项与性能考量

  1. 内存消耗: NumPy广播生成 n * m 的布尔矩阵。如果 df1 和 df2 的行数 n 和 m 都非常大(例如,数百万行),那么这个 n * m 的矩阵可能会消耗巨大的内存,甚至导致内存溢出。在这种极端情况下,可能需要考虑其他更复杂的解决方案,例如分块处理、使用专门的区间树数据结构,或者数据库级别的区间连接功能。
  2. 索引重置: 在使用 iloc 之前重置索引 (reset_index(drop=True)) 是一个好习惯,可以避免因原始数据框索引不连续或重复而导致的问题。
  3. 条件扩展: NumPy广播的优势在于其灵活性。如果需要添加更多合并条件(例如,除了时间范围匹配外,还需要某个属性也匹配),可以轻松地在 match_matrix 的计算中添加额外的布尔条件,例如 (t1 <= t3) & (t3 <= t2) & (df1['attr_a'].to_numpy()[:, None] == df2['attr_b'].to_numpy())。
  4. 时间精度: 确保所有时间列都转换为 datetime 对象,并且精度一致,以避免比较错误。

总结

利用NumPy的广播机制是解决Pandas中基于时间范围进行数据框合并的强大且高效的方法。它将原本需要嵌套循环的 O(n*m) 操作转化为高度优化的底层数组操作,显著提升了处理大规模数据的性能。虽然需要警惕内存消耗,但在大多数常见场景下,这种方法都是实现此类复杂合并操作的首选“Pandas-y”解决方案。

热门AI工具

更多
豆包大模型

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

UpDream
UpDream Hot

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

UP简历
UP简历 Hot

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

AionClaw
AionClaw Hot

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

WorkBuddy

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

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

墨刀AI
墨刀AI Hot

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

DeepSeek

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

Laper
Laper Hot

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

相关专题

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

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

300

2025.12.04

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

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

212

2026.01.31

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

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

371

2026.04.13

treenode的用法
treenode的用法

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

2261

2023.12.01

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

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

336

2025.12.22

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

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

357

2026.01.06

C++ 数据结构与算法实现教程合集
C++ 数据结构与算法实现教程合集

以 C++ 为实现语言,系统讲解核心数据结构与算法,涵盖链表(单链表/双链表/环检测)、栈与队列(单调栈/优先队列)、二叉树(遍历/BST/AVL/红黑树)、哈希表(开地址法/链地址法)、图(邻接表/BFS/DFS/Dijkstra/拓扑排序)、常见排序算法(快排/归并/堆排/计数排序)的实现与复杂度分析,同时分享 LeetCode 刷题技巧、竞赛编程常用模板(二分/前缀和/滑动窗口/动态规划),帮助开发者夯实算法基础。

412

2026.05.09

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

2405

2023.06.29

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

20

2026.09.30

热门下载

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

精品课程

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

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