如何高效将粗粒度深度地质数据重采样到Pandas细粒度DataFrame
高效实现地质钻孔数据的粗粒度标签映射到细粒度DataFrame
问题背景
我有两组地质钻孔数据:
- 粗粒度DataFrame:按钻孔名称(
DDH_name)、起始深度(From_ft)、结束深度(To_ft)组织,包含离散标签字段ALT1(不可插值),示例如下:
| DDH_name | From_ft | To_ft | ALT1 | |
|---|---|---|---|---|
| 0 | A-7CD5 | 0.0 | 90.0 | 20 |
| 1 | A-7CD5 | 90.0 | 110.0 | 70 |
| 3 | A-7CD5 | 110.0 | 150.0 | 7 |
- 细粒度DataFrame:深度间隔为1ft,同样按
DDH_name、From_ft、To_ft组织,需要将粗粒度的ALT1标签映射到对应深度范围的细粒度行中——比如粗粒度0-90ft区间的ALT1=20要覆盖细粒度中该范围内的所有行。
当前用逐行循环实现的代码虽能得到预期结果,但效率极低,处理10万行细粒度数据耗时约30秒:
当前低效代码
df['ALT1'] = '' for i in df.index: w = df['DDH_name'].iloc[i] d = df['From_ft'].iloc[i] try: df['ALT1'][i] = df_alter[df_alter['DDH_name']==w][df_alter['From_ft']<=d][df_alter['To_ft']>d]['ALT1'].values[0] except: pass
预期结果示例(截取90ft前后片段)
| DDH_name | From_ft | To_ft | ALT1 | |
|---|---|---|---|---|
| 85 | A-7CD5 | 85.0 | 86.0 | 20 |
| 86 | A-7CD5 | 86.0 | 87.0 | 20 |
| 87 | A-7CD5 | 87.0 | 88.0 | 20 |
| 88 | A-7CD5 | 88.0 | 89.0 | 20 |
| 89 | A-7CD5 | 89.0 | 90.0 | 20 |
| 90 | A-7CD5 | 90.0 | 91.0 | 70 |
| 91 | A-7CD5 | 91.0 | 92.0 | 70 |
| 92 | A-7CD5 | 92.0 | 93.0 | 70 |
高效解决方案
方法1:使用merge_asof(推荐)
利用Pandas内置的merge_asof函数,按钻孔名称分组后基于深度做近似匹配,完全规避逐行循环,是这类区间映射场景的最优解:
import pandas as pd # 先对两组数据按钻孔名称+起始深度排序(merge_asof要求输入已排序) df_alter_sorted = df_alter.sort_values(['DDH_name', 'From_ft']) df_sorted = df.sort_values(['DDH_name', 'From_ft']) # 执行按组的近似合并:匹配细粒度深度对应的最近的粗粒度起始深度 result = pd.merge_asof( df_sorted, df_alter_sorted[['DDH_name', 'From_ft', 'ALT1', 'To_ft']], on='From_ft', by='DDH_name', direction='backward' ) # 验证深度区间有效性(确保细粒度深度落在粗粒度的[From_ft, To_ft)区间内) result = result[result['From_ft'] < result['To_ft']] # 整理列名并恢复原索引顺序 result = result.rename(columns={'From_ft_x': 'From_ft'}).drop(columns=['From_ft_y', 'To_ft_y']) result = result.sort_index()
方法2:区间索引+分组映射
为每个钻孔的粗粒度数据创建深度区间索引,再批量映射到细粒度数据:
def map_alt1_to_group(group): # 获取当前钻孔的粗粒度数据 coarse_data = df_alter[df_alter['DDH_name'] == group.name] # 创建左闭右开的深度区间索引 depth_intervals = pd.IntervalIndex.from_arrays( coarse_data['From_ft'], coarse_data['To_ft'], closed='left' ) # 匹配细粒度深度到对应区间,提取ALT1值 group['ALT1'] = coarse_data.set_index(depth_intervals).reindex( depth_intervals.get_indexer(group['From_ft']) )['ALT1'].values return group # 按钻孔分组处理细粒度数据 result = df.groupby('DDH_name', group_keys=False).apply(map_alt1_to_group)
性能说明
两种方法均采用Pandas向量化操作,处理10万行细粒度数据的耗时可控制在1秒以内,效率远超原循环方案。
内容的提问来源于stack exchange,提问作者GlenB
相关产品推荐
相关产品推荐

