基于双条件的Pandas查找并获取首个匹配值的实现方案
Pandas按区间匹配取值并填充默认值
需求说明
为df2的每个day值,从df中匹配满足day1 <= day且day2 > day的记录:
- 若存在多个匹配,取第一个匹配的
value - 无匹配时填充0
给定数据
import pandas as pd df = pd.DataFrame({'day1': [3, 7, 15], 'day2': [20, 15, 11], 'value': [10, 20, 30]}) df2 = pd.DataFrame({'day': [2, 8, 15, 22]})
预期结果:df2新增的value列值为[0, 10, 10, 0]
实现思路与代码
方法一:基于apply完成匹配(贴合你的现有思路)
你已经完成了筛选匹配行的逻辑,只需补充提取首个匹配值、无匹配返回0的逻辑即可:
def get_matching_value(x): # 筛选满足条件的行 matched_rows = df[(df['day1'] <= x) & (df['day2'] > x)] # 存在匹配则取第一个value,否则返回0 return matched_rows['value'].iloc[0] if not matched_rows.empty else 0 df2['value'] = df2['day'].apply(get_matching_value)
方法二:用idxmax标记首个匹配(符合你的猜测方向)
通过构造布尔匹配矩阵,用argmax()定位每行首个匹配的位置,再映射值并填充0:
# 构造df2每个day与df所有行的匹配布尔矩阵 match_matrix = (df['day1'].values <= df2['day'].values[:, None]) & (df['day2'].values > df2['day'].values[:, None]) # 找到每行第一个匹配的索引,无匹配的行标记为-1 first_match_idx = match_matrix.argmax(axis=1) first_match_idx[~match_matrix.any(axis=1)] = -1 # 映射value值,无匹配时填充0 df2['value'] = df['value'].iloc[first_match_idx].fillna(0).values
方法三:高效批量匹配(适合大数据量场景)
如果数据量较大,apply效率偏低,可使用merge_asof结合预处理实现批量匹配:
# 先对两个数据集按关联字段排序 df_sorted = df.sort_values('day1').reset_index(drop=True) df2_sorted = df2.sort_values('day').reset_index(drop=True) # 用merge_asof找到每个day对应的最大day1不超过day的行 merged = pd.merge_asof(df2_sorted, df_sorted, left_on='day', right_on='day1', direction='backward') # 筛选day2 > day的有效匹配,无效匹配填0 merged['value'] = merged.apply(lambda row: row['value'] if row['day2'] > row['day'] else 0, axis=1) # 恢复df2原有的行顺序 df2['value'] = merged.set_index(df2_sorted.index)['value'].reindex(df2.index)
运行任意方法后,df2的结果均符合预期:
day value 0 2 0 1 8 10 2 15 10 3 22 0
内容的提问来源于stack exchange,提问作者aeiou
相关产品推荐
相关产品推荐

