如何为钻孔测试数据匹配对应岩性深度区间?
Pandas高效合并钻孔测试数据与岩性区间数据
首先,咱们可以用Pandas原生的merge_asof函数完美解决这个问题——这工具天生就是为这类「按分组匹配最近符合条件值」的场景设计的,比用循环或者数据库关联的方式高效得多,完全贴合你的需求。
步骤详解
1. 先准备示例数据(方便你复现验证)
先把你给出的两个DataFrame构建出来:
import pandas as pd tests = pd.DataFrame({ 'borehole': ['B-1', 'B-1', 'B-42', 'B-42', 'B-42', 'B-42', 'B-09', 'B-09', 'B-09'], 'depthTest': [1.5, 20.0, 1.0, 2.0, 15.0, 30.0, 1.0, 10.0, 15.0] }) liths = pd.DataFrame({ 'borehole': ['B-1', 'B-1', 'B-1', 'B-42', 'B-42', 'B-42', 'B-09', 'B-09'], 'depthTop': [0, 5, 18, 0, 1, 26, 0, 12], 'lith': ['sand', 'clay', 'shale', 'sand', 'clay', 'shale', 'sand', 'shale'] })
2. 对两个数据集排序
merge_asof有个硬性要求:分组键(by)和匹配用的深度列必须是已排序的,所以先给两个表按钻孔+深度升序排好:
# 岩性数据按钻孔、顶部深度排序 liths_sorted = liths.sort_values(['borehole', 'depthTop']) # 测试数据按钻孔、测试深度排序 tests_sorted = tests.sort_values(['borehole', 'depthTest'])
3. 用merge_asof完成匹配合并
核心操作就在这一步:按钻孔分组,为每个测试深度找到小于等于它的最大顶部深度对应的岩性:
result = pd.merge_asof( tests_sorted, liths_sorted, by='borehole', # 按钻孔分组,只在同钻孔内匹配 left_on='depthTest', # 测试数据里的匹配深度列 right_on='depthTop', # 岩性数据里的顶部深度列 direction='backward' # 指定找「小于等于left_on值」的最近right_on值 )
4. 整理成目标格式
最后只保留需要的列,要是想恢复原始tests的顺序,再加个按索引排序就行:
# 提取目标列,可选恢复原始顺序 result = result[['borehole', 'depthTest', 'lith']].sort_index()
运行后得到的结果和你给出的示例完全一致:
borehole depthTest lith 0 B-1 1.5 sand 1 B-1 20.0 shale 2 B-42 1.0 clay 3 B-42 2.0 clay 4 B-42 15.0 clay 5 B-42 30.0 shale 6 B-09 1.0 sand 7 B-09 10.0 sand 8 B-09 15.0 shale
为什么这个方法高效?
merge_asof是基于排序后的线性扫描实现的,时间复杂度主要来自排序步骤(O(n log n)),相比循环遍历每个钻孔的暴力方法(O(n*m)),在数据量较大时效率提升非常明显,完全是Pandas原生的向量化操作,性能拉满。
内容的提问来源于stack exchange,提问作者cfort
相关产品推荐
相关产品推荐

