0

0

Pandas中基于IntervalIndex实现高效区间匹配与数据关联

心靈之曲

心靈之曲

发布时间:2025-10-27 13:28:27

|

224人浏览过

|

来源于php中文网

原创

Pandas中基于IntervalIndex实现高效区间匹配与数据关联

本教程探讨了在pandas中如何高效地实现基于数值范围的数据匹配与数据合并。针对传统`merge`函数无法直接处理区间匹配的场景,我们介绍了利用`pd.intervalindex`构建区间索引,并通过`get_indexer`方法将主表数据关联到对应的区间,最终实现精准的范围查找与值填充,有效解决了复杂的数据关联难题。

在数据分析和处理中,我们经常需要将两个数据集基于某个条件进行合并。当条件是精确值匹配时,Pandas的merge函数非常强大且高效。然而,当合并条件涉及到“一个值是否落入另一个数据框中定义的某个数值区间”时,传统的merge方法或直接的布尔索引往往会遇到挑战,因为它们无法直接处理这种非等值的范围匹配关系。

问题场景与挑战

假设我们有两个DataFrame:

  1. df 包含一系列序列号(serial),我们需要为每个序列号查找其对应的作业(Job)。
  2. df2 包含作业信息,其中每个作业由一个起始序列号(StartSerial)和一个结束序列号(StopSerial)定义,并关联一个作业编号(Job)。

我们的目标是,如果df中的serial值落在df2中某个StartSerial和StopSerial定义的区间内,就将对应的Job值填充到df中。

以下是示例数据:

import pandas as pd
import numpy as np

num = {'serial':[10,20,30,50]}
df = pd.DataFrame(num)
print("DataFrame df:")
print(df)

cols = {'StartSerial':[9,19,29,39],'StopSerial':[15,25,35,45],'Job':[564,859,748,125]}
df2 = pd.DataFrame(cols)
print("\nDataFrame df2:")
print(df2)

输出:

TeemIp - IPAM and DDI solution
TeemIp - IPAM and DDI solution

TeemIp是一个免费、开源、基于WEB的IP地址管理(IPAM)工具,提供全面的IP管理功能。它允许您管理IPv4、IPv6和DNS空间:跟踪用户请求,发现和分配IP,管理您的IP计划、子网空间、区域和DNS记录,符合最佳的DDI实践。同时,TeemIp的配置管理数据库(CMDB)允许您管理您的IT库存并将您的配置项(CIs)与它们使用的IP关联起来。项目源代码位于https://github.com/TeemIP

下载
DataFrame df:
   serial
0      10
1      20
2      30
3      50

DataFrame df2:
   StartSerial  StopSerial  Job
0            9          15  564
1           19          25  859
2           29          35  748
3           39          45  125

尝试使用直接的布尔索引或np.where通常会失败,因为这些操作是按行进行的,而我们期望的是跨行匹配:

# 错误尝试1:直接使用np.where
# df['Job'] = np.where((df['serial'] >= df2['StartSerial']) & (df['serial'] <= df2['StopSerial']), df2['Job'], '')
# 这会因为df和df2的长度或索引不匹配而导致值无法正确广播。

# 错误尝试2:使用df.loc进行条件赋值
# df.loc[(df['serial'] >= df2['StartSerial']) & (df['serial'] <= df2['StopSerial']), 'Job'] = df2['Job']
# 同样,这种方式无法实现跨DataFrame的行级别区间匹配。

上述方法无法正确执行,因为它们试图在不同DataFrame的行之间直接进行元素级比较,而不是进行区间查找。

解决方案:利用 pd.IntervalIndex 进行区间匹配

Pandas提供了一个强大的数据结构 pd.IntervalIndex,专门用于表示和操作区间数据。它非常适合解决这类基于范围的查找问题。

pd.IntervalIndex 的核心思想是将一个DataFrame的列(例如StartSerial和StopSerial)转换为一个区间索引,然后可以使用这个索引来高效地查找另一个DataFrame中的值(例如serial)属于哪个区间。

步骤一:创建 pd.IntervalIndex

首先,我们从 df2 的 StartSerial 和 StopSerial 列创建一个 pd.IntervalIndex。closed 参数用于指定区间的闭合性,例如 'both' 表示两端都包含,'left' 表示左闭右开等。

# 从df2的起始和结束序列号创建IntervalIndex
# closed="both" 表示区间 [StartSerial, StopSerial] 是闭合的
idx = pd.IntervalIndex.from_arrays(df2.StartSerial, df2.StopSerial, closed="both")
print("\nCreated IntervalIndex:")
print(idx)

输出:

Created IntervalIndex:
IntervalIndex([[9, 15], [19, 25], [29, 35], [39, 45]],
              closed='both',
              dtype='interval[int64]')

步骤二:使用 get_indexer 查找匹配的区间索引

IntervalIndex 对象有一个 get_indexer 方法,它接受一个数组(例如 df 的 serial 列)作为输入,并返回一个整数数组,表示输入数组中每个元素在 IntervalIndex 中的位置。如果某个值没有落在任何区间内,则返回 -1。

# 使用IntervalIndex的get_indexer方法查找df.serial中每个值对应的区间索引
# 这将返回df2中对应行的索引
indexer = idx.get_indexer(df.serial)
print("\nIndexer array (df2 row indices):")
print(indexer)

输出:

Indexer array (df2 row indices):
[ 0  1  2 -1]

可以看到,serial 为 10 对应 df2 的第 0 行(区间 [9, 15]),20 对应第 1 行,30 对应第 2 行。而 50 没有落在任何区间内,因此返回 -1。

步骤三:根据索引填充 Job 值

现在我们有了 df 中每个 serial 值对应的 df2 行索引。我们可以利用这些索引来从 df2 中提取 Job 值并将其分配给 df。

由于 get_indexer 返回的索引可能包含 -1(表示无匹配),我们需要先处理这些无效索引。一种常见的方法是创建一个与 df 长度相同的空列,然后根据有效的 indexer 值进行填充。

# 初始化df中的'Job'列为NaN
df['Job'] = np.nan

# 找到有效的索引(即不为-1的索引)
valid_indices_in_df = (indexer != -1)
valid_indices_in_df2 = indexer[valid_indices_in_df]

# 将df2中对应Job值赋给df的Job列
# 注意:这里直接使用df2.loc[valid_indices_in_df2, 'Job']来获取Job值
# 然后赋值给df.loc[valid_indices_in_df, 'Job']
df.loc[valid_indices_in_df, 'Job'] = df2.loc[valid_indices_in_df2, 'Job'].values

print("\nFinal DataFrame with matched Jobs:")
print(df)

输出:

Final DataFrame with matched Jobs:
   serial    Job
0      10  564.0
1      20  859.0
2      30  748.0
3      50    NaN

这正是我们期望的结果。serial 为 50 的行因为没有找到匹配的区间,所以 Job 列为 NaN。

完整代码示例

将上述步骤整合到一起,形成完整的解决方案:

import pandas as pd
import numpy as np

# 原始数据
num = {'serial':[10,20,30,50]}
df = pd.DataFrame(num)

cols = {'StartSerial':[9,19,29,39],'StopSerial':[15,25,35,45],'Job':[564,859,748,125]}
df2 = pd.DataFrame(cols)

# 1. 创建 pd.IntervalIndex
idx = pd.IntervalIndex.from_arrays(df2.StartSerial, df2.StopSerial, closed="both")

# 2. 使用 get_indexer 查找匹配的区间索引
indexer = idx.get_indexer(df.serial)

# 3. 初始化df中的'Job'列为NaN,并根据有效索引填充
df['Job'] = np.nan
valid_indices_in_df = (indexer != -1)
valid_indices_in_df2 = indexer[valid_indices_in_df]

# 确保df2.loc[valid_indices_in_df2, 'Job']的索引与df.loc[valid_indices_in_df, 'Job']的索引对齐
# 最简单的方式是获取其values进行赋值,避免索引不对齐的问题
df.loc[valid_indices_in_df, 'Job'] = df2.loc[valid_indices_in_df2, 'Job'].values

print("\n最终结果:")
print(df)

注意事项与总结

  • 闭合性 (closed 参数): pd.IntervalIndex.from_arrays 的 closed 参数非常重要,它决定了区间的包含关系。
    • 'left':左闭右开 [a, b)
    • 'right':左开右闭 (a, b]
    • 'both':两端都闭合 [a, b] (默认值)
    • 'neither':两端都开 (a, b) 根据您的业务需求选择正确的闭合性。
  • 性能: pd.IntervalIndex 内部通常使用优化过的结构(如二叉搜索树),因此对于大规模数据集的区间查找,它的性能通常优于循环或复杂的条件判断。
  • NaN 处理: 如果 serial 值没有落在任何区间内,get_indexer 返回 -1。在赋值时,这些未匹配的行将保留 NaN,这通常是期望的行为。
  • 多列匹配: 如果需要基于多个条件(例如,除了序列号范围,还要匹配一个类型字段),可能需要先对数据进行分组,然后在每个组内应用 IntervalIndex 匹配,或者考虑更复杂的索引结构。

通过 pd.IntervalIndex,Pandas提供了一种优雅且高效的方式来解决复杂的区间匹配问题,极大地简化了这类数据关联任务的实现。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

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

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

70

2025.12.04

treenode的用法
treenode的用法

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

539

2023.12.01

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

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

21

2025.12.22

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

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

28

2026.01.06

treenode的用法
treenode的用法

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

539

2023.12.01

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

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

21

2025.12.22

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

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

28

2026.01.06

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

8

2026.01.30

c++ 字符串格式化
c++ 字符串格式化

本专题整合了c++字符串格式化用法、输出技巧、实践等等内容,阅读专题下面的文章了解更多详细内容。

8

2026.01.30

热门下载

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

精品课程

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

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