如何为DataFrame行添加对应地层深度区间的唯一流体码列表?
问题
现有两个Pandas DataFrame:
- formation_top:存储地层名称及其顶部深度,数据如下:
import pandas as pd import numpy as np formation_top = pd.DataFrame( {'Formation': ['Balakhany', 'Balakhany X', 'Pereriv A', 'Pereviv B'], 'Depth': [2200, 2250, 2300, 2340]} )
对应表格:
| Formation | Depth |
|---|---|
| Balakhany | 2200 |
| Balakhany X | 2250 |
| Pereriv A | 2300 |
| Pereviv B | 2340 |
每个地层的深度区间为当前顶部深度至下一个地层的顶部深度,例如Balakhany对应2200-2250米;最后一个地层Pereviv B的区间为2340-2400米(因fluidcode数据覆盖至2400米)。
- fluidcode:包含2200至2400米、间隔1米的Depth列,以及对应深度的FLUIDCODE列,数据示例如下:
# 模拟示例数据 fluidcode = pd.DataFrame( {'Depth': range(2200, 2401), 'FLUIDCODE': np.where(range(2200,2250) == 2202, 4, np.where(range(2200,2250) == 2210,6,3))} ) # 补充后续深度的示例值 fluidcode.loc[fluidcode['Depth'].between(2250,2300), 'FLUIDCODE'] = 5 fluidcode.loc[fluidcode['Depth'].between(2300,2340), 'FLUIDCODE'] = np.nan fluidcode.loc[fluidcode['Depth'].isin([2338,2339]), 'FLUIDCODE'] = [2,7] fluidcode.loc[fluidcode['Depth'] ==2340, 'FLUIDCODE'] = np.nan
示例表格片段:
| FLUIDCODE | Depth |
|---|---|
| 3 | 2200 |
| 3 | 2201 |
| 4 | 2202 |
| ... | ... |
| 2 | 2338 |
| 7 | 2339 |
| np.nan | 2340 |
需求
提取每个地层深度区间内的唯一流体码,将其列表添加到formation_top的新FLUIDCODES列中。
尝试代码及报错
尝试了以下代码:
formation_top['FLUIDCODES'] = np.nan for i in range(len(formation_top) - 1): depth_condition = (fluidcode['Depth'] >= formation_top['Depth'][i]) & (fluidcode['Depth'] <= formation_top['Depth'][i + 1]) unique_flcodes = fluidcode.loc[depth_condition, 'FLUIDCODE'].unique() unique_flcodes = pd.Series([unique_flcodes]) formation_top.at[i, 'FLUIDCODES'] = unique_flcodes
出现报错:
ValueError: Incompatible indexer with Series
期望输出
Formation Depth FLUIDCODES 0 Balakhany 2200 [3, 4, 6] 1 Balakhany X 2250 [5] 2 Pereriv A 2300 NaN 3 Pereriv B 2340 [2, 7]
解决方案
报错原因
你尝试将pd.Series类型的值赋值给DataFrame的单个单元格,而at方法仅支持标量或可哈希对象,因此引发索引不兼容错误。正确做法是直接将唯一值的列表(过滤NaN后)赋值给单元格。
正确实现代码
import pandas as pd import numpy as np # 初始化FLUIDCODES列为NaN formation_top['FLUIDCODES'] = np.nan # 处理前n-1个地层 for i in range(len(formation_top) - 1): start_depth = formation_top['Depth'].iloc[i] end_depth = formation_top['Depth'].iloc[i+1] # 左闭右开区间筛选,避免深度边界重复计算,需包含下一个顶部深度可改为<= mask = (fluidcode['Depth'] >= start_depth) & (fluidcode['Depth'] < end_depth) # 获取唯一值并过滤空值 unique_codes = fluidcode.loc[mask, 'FLUIDCODE'].dropna().unique() # 有有效码则赋值列表,否则保留NaN if len(unique_codes) > 0: formation_top.at[i, 'FLUIDCODES'] = unique_codes.tolist() # 单独处理最后一个地层(2340至2400米) last_idx = len(formation_top) - 1 last_start = formation_top['Depth'].iloc[last_idx] last_mask = fluidcode['Depth'] >= last_start last_unique_codes = fluidcode.loc[last_mask, 'FLUIDCODE'].dropna().unique() if len(last_unique_codes) > 0: formation_top.at[last_idx, 'FLUIDCODES'] = last_unique_codes.tolist()
代码说明
- 区间筛选:前n-1个地层使用
[start_depth, end_depth)左闭右开区间,避免相邻地层的深度边界重复计算;若需求包含下一个地层顶部深度,可将<改为<=。 - 空值过滤:用
dropna()排除FLUIDCODE中的NaN,避免空值混入结果列表。 - 赋值逻辑:直接将唯一值数组转为列表后,用
at赋值给单元格,规避Series类型不兼容问题。 - 最后地层处理:单独处理无后续地层的最后一行,区间为自身顶部深度至fluidcode的最大深度。
最终输出
运行后得到的formation_top如下:
| Formation | Depth | FLUIDCODES |
|---|---|---|
| Balakhany | 2200 | [3, 4, 6] |
| Balakhany X | 2250 | [5] |
| Pereriv A | 2300 | NaN |
| Pereviv B | 2340 | [2, 7] |
内容的提问来源于stack exchange,提问作者Mahammad Ojagzada
相关产品推荐
相关产品推荐

