
本教程探讨了在pandas中如何高效地实现基于数值范围的数据匹配与数据合并。针对传统`merge`函数无法直接处理区间匹配的场景,我们介绍了利用`pd.intervalindex`构建区间索引,并通过`get_indexer`方法将主表数据关联到对应的区间,最终实现精准的范围查找与值填充,有效解决了复杂的数据关联难题。
在数据分析和处理中,我们经常需要将两个数据集基于某个条件进行合并。当条件是精确值匹配时,Pandas的merge函数非常强大且高效。然而,当合并条件涉及到“一个值是否落入另一个数据框中定义的某个数值区间”时,传统的merge方法或直接的布尔索引往往会遇到挑战,因为它们无法直接处理这种非等值的范围匹配关系。
假设我们有两个DataFrame:
我们的目标是,如果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)输出:
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的行之间直接进行元素级比较,而不是进行区间查找。
Pandas提供了一个强大的数据结构 pd.IntervalIndex,专门用于表示和操作区间数据。它非常适合解决这类基于范围的查找问题。
pd.IntervalIndex 的核心思想是将一个DataFrame的列(例如StartSerial和StopSerial)转换为一个区间索引,然后可以使用这个索引来高效地查找另一个DataFrame中的值(例如serial)属于哪个区间。
首先,我们从 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]')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。
现在我们有了 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)通过 pd.IntervalIndex,Pandas提供了一种优雅且高效的方式来解决复杂的区间匹配问题,极大地简化了这类数据关联任务的实现。
以上就是Pandas中基于IntervalIndex实现高效区间匹配与数据关联的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号