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

统计DataFrame单元格值在另一DataFrame中的出现次数(含容差)

问题:基于1%容差统计DataFrame价格出现次数,能否避免迭代?可用merge_asof+分组吗?

现有两个结构一致的DataFrame:
dfA:

IndexPrice
010.21
112.21

dfB:

IndexPrice
010.21
110.24
211.32
312.21

需求:给dfA新增Occurrences列,统计每个Price值在dfB中满足1%容差(即Price×0.99 ≤ 目标Price ≤ Price×1.01)的出现次数,预期结果如下:

IndexPriceOccurrences
010.212
112.211

请问能否避免迭代实现?是否可使用merge_asof结合分组统计的方法?


回答

完全可以避免迭代,merge_asof结合分组的思路可行,同时还有性能更优的批量统计方案,以下是具体实现:

方案1:高效批量统计(无迭代,适合大数据量)

利用排序后的二分查找快速定位容差区间,直接计算匹配次数,全程无循环:

import pandas as pd

# 构造示例数据
dfA = pd.DataFrame({'Price': [10.21, 12.21]})
dfB = pd.DataFrame({'Price': [10.21, 10.24, 11.32, 12.21]})

# 对dfB的Price排序(二分查找的必要前提)
dfB_sorted_prices = dfB['Price'].sort_values().values

# 计算dfA每个Price的1%容差上下限
dfA['lower'] = dfA['Price'] * 0.99
dfA['upper'] = dfA['Price'] * 1.01

# 用searchsorted定位区间边界,计算匹配次数
dfA['Occurrences'] = [
    dfB_sorted_prices.searchsorted(upper, side='right') - dfB_sorted_prices.searchsorted(lower, side='left')
    for lower, upper in zip(dfA['lower'], dfA['upper'])
]

# 整理得到结果
result = dfA[['Price', 'Occurrences']]

方案2:merge_asof+分组(满足需求的思路)

merge_asof本身是有序近邻匹配工具,要实现计数需要先关联所有符合条件的记录,再分组统计:

# 排序数据(merge_asof要求左右表按连接键排序)
dfA_sorted = dfA.sort_values('Price').reset_index()
dfB_sorted = dfB.sort_values('Price').reset_index(drop=True)

# 计算容差范围
dfA_sorted['lower'] = dfA_sorted['Price'] * 0.99
dfA_sorted['upper'] = dfA_sorted['Price'] * 1.01

# 交叉连接所有记录,过滤出符合容差的条目
cross_join = dfA_sorted.merge(dfB_sorted, how='cross')
filtered_records = cross_join[(cross_join['Price_y'] >= cross_join['lower']) & (cross_join['Price_y'] <= cross_join['upper'])]

# 按dfA原索引分组统计匹配次数
counts = filtered_records.groupby('index')['Price_y'].count().rename('Occurrences')

# 合并回原dfA得到结果
result = dfA.join(counts)

方案3:分组优化(针对dfA有重复Price的场景)

如果dfA存在重复Price值,先按Price分组计算每组的匹配次数,再合并回原表:

dfB_sorted_prices = dfB['Price'].sort_values().values

# 对dfA按Price分组,计算每组的容差匹配次数
price_counts = dfA.groupby('Price').apply(
    lambda x: dfB_sorted_prices.searchsorted(x['Price'].iloc[0]*1.01, side='right') - 
              dfB_sorted_prices.searchsorted(x['Price'].iloc[0]*0.99, side='left')
).rename('Occurrences').reset_index()

# 合并回原dfA得到结果
result = dfA.merge(price_counts, on='Price', how='left')

结论

  • 所有方案都完全避免了迭代操作,效率远高于循环遍历。
  • merge_asof更适合一对一的近邻匹配场景,交叉连接+分组的方式可行但数据量大时内存占用较高;二分查找+区间统计是性能最优的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 15:07:38