You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas DataFrame区间匹配:两个含深度区间的DataFrame匹配需求

Pandas深度区间匹配解决方案

我经常处理这类地质/测井数据的区间匹配需求,刚好能给你一些实用的解决方案。核心目标就是把两个DataFrame中同ID下存在重叠(或包含关系)的深度区间关联起来,将file_2的参数匹配到对应的file_1区间中。下面分几种场景给出实现方法:

先准备示例数据(方便你测试)

import pandas as pd

# 模拟你的file_1数据
file_1 = pd.DataFrame({
    'ID': ['HLD032', 'HLD032', 'HLD650'],
    'Depth_From': [611.10, 612.00, 597.40],
    'Depth_To': [612.00, 612.20, 598.10]
})

# 模拟你的file_2数据
file_2 = pd.DataFrame({
    'ID': ['HLD032', 'HLD032', 'HLD650'],
    'Depth_From': [611.00, 612.10, 597.00],
    'Depth_To': [612.00, 612.30, 598.50],
    'Infill': [0.2, 0.5, 0.1],
    'Roughness': [1.2, 2.1, 0.8],
    'Thickness': [0.9, 0.2, 0.7]
})

方法一:基础Merge+条件筛选(适合小数据量)

这种方法逻辑简单,先按ID合并两个DataFrame,再筛选出区间重叠的行:

# 按ID合并,生成同ID的所有区间组合
merged = pd.merge(file_1, file_2, on='ID', suffixes=('_file1', '_file2'))

# 筛选区间重叠的行:两个区间存在交集的条件
# 即file1的起始深度 ≤ file2的结束深度,且file1的结束深度 ≥ file2的起始深度
matched = merged[
    (merged['Depth_From_file1'] <= merged['Depth_To_file2']) & 
    (merged['Depth_To_file1'] >= merged['Depth_From_file2'])
]

# 整理结果列名,保留需要的字段
result = matched.rename(columns={
    'Depth_From_file1': 'Depth_From',
    'Depth_To_file1': 'Depth_To'
})[['ID', 'Depth_From', 'Depth_To', 'Infill', 'Roughness', 'Thickness']]

print(result)

方法二:Groupby+Apply(适合大数据量)

如果你的数据量很大(比如像你说的1万+行),直接Merge会生成大量冗余行,效率很低。这种情况下,按ID分组后再处理每个组的区间匹配会更高效:

def match_single_id_intervals(group_file1, group_file2):
    """处理单个ID下的区间匹配"""
    matches = []
    # 遍历file1当前ID的每一行区间
    for _, row_file1 in group_file1.iterrows():
        # 筛选file2中与当前区间重叠的行
        overlap_mask = (
            group_file2['Depth_From'] <= row_file1['Depth_To']
            ) & (
            group_file2['Depth_To'] >= row_file1['Depth_From']
        )
        matched_rows = group_file2[overlap_mask].copy()
        # 带上file1的区间信息
        matched_rows['File1_Depth_From'] = row_file1['Depth_From']
        matched_rows['File1_Depth_To'] = row_file1['Depth_To']
        matches.append(matched_rows)
    
    return pd.concat(matches) if matches else pd.DataFrame()

# 按ID分组
grouped_file1 = file_1.groupby('ID')
grouped_file2 = file_2.groupby('ID')

# 只处理两个DataFrame都存在的ID
common_ids = set(grouped_file1.groups.keys()) & set(grouped_file2.groups.keys())

# 逐个ID处理并合并结果
final_result = pd.concat([
    match_single_id_intervals(grouped_file1.get_group(id), grouped_file2.get_group(id))
    for id in common_ids
]).reset_index(drop=True)

# 调整列顺序,让结果更清晰
final_result = final_result[
    ['ID', 'File1_Depth_From', 'File1_Depth_To', 'Depth_From', 'Depth_To', 'Infill', 'Roughness', 'Thickness']
]

print(final_result)

进阶:用IntervalTree加速超大数据集

如果你的数据量达到几十万甚至上百万行,上面的循环方法还是会慢。可以用专门处理区间查询的intervaltree库来大幅提升效率:

首先安装库:

pip install intervaltree

然后实现代码:

from intervaltree import IntervalTree

def match_with_intervaltree(group_file1, group_file2):
    """用IntervalTree加速区间匹配"""
    # 构建file2的区间树,每个区间对应一行数据
    interval_tree = IntervalTree()
    for _, row in group_file2.iterrows():
        interval_tree.addi(row['Depth_From'], row['Depth_To'], row)
    
    matches = []
    for _, row_file1 in group_file1.iterrows():
        # 查询所有与当前区间重叠的file2区间
        overlapping_intervals = interval_tree.search(row_file1['Depth_From'], row_file1['Depth_To'])
        for interval in overlapping_intervals:
            matched_row = interval.data.copy()
            matched_row['File1_Depth_From'] = row_file1['Depth_From']
            matched_row['File1_Depth_To'] = row_file1['Depth_To']
            matches.append(matched_row)
    
    return pd.DataFrame(matches) if matches else pd.DataFrame()

# 用法和Groupby方法一致,替换match_single_id_intervals函数即可

关键注意事项

  • 匹配条件调整:上面的代码用的是「区间有交集」的规则,如果你的需求是「file1的区间完全被file2的区间包含」,只需把筛选条件改成:
    # 完全包含的条件:file2的起始深度 ≤ file1的起始深度,且file2的结束深度 ≥ file1的结束深度
    mask = (group_file2['Depth_From'] <= row_file1['Depth_From']) & (group_file2['Depth_To'] >= row_file1['Depth_To'])
    
  • 一对多聚合:如果一个file1区间匹配到多个file2区间,可以对参数做聚合处理(比如取平均值、求和):
    agg_result = final_result.groupby(['ID', 'File1_Depth_From', 'File1_Depth_To']).agg({
        'Infill': 'mean',
        'Roughness': 'max',
        'Thickness': 'sum'
    }).reset_index()
    
  • 数据类型检查:确保ID列和深度列的类型一致(比如ID是字符串,深度是float),避免匹配错误。

内容的提问来源于stack exchange,提问作者Tani84

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:20:09