如何高效判断pandas DataFrame列值是否落在另一DataFrame给定区间内
高效实现方案
你原来的方案复杂度为O(N*M)(N为采样点数量、M为区间数量),20万次全量遍历6千万行数据必然速度极慢,推荐以下两种经过性能优化的方案:
方案1:通用区间匹配方案(兼容任意顺序的tSample)
直接使用Pandas内置的IntervalIndex做区间索引匹配,底层基于树结构查询,复杂度为O(N log M),是最简便的实现:
import pandas as pd import numpy as np # 构造闭区间的区间索引,和你原逻辑中between的闭区间规则一致 fix_intervals = pd.IntervalIndex.from_arrays( left=dfFixations['tStart'], right=dfFixations['tEnd'], closed='both' ) # 批量查询每个tSample所属的区间索引,返回-1代表没有落在任何区间 match_index = fix_intervals.get_indexer(dfSamples['tSample']) # 批量打标签 dfSamples['labels'] = np.where(match_index != -1, 'fixation', 'no_fixation')
该方案在普通家用CPU上处理6千万行数据耗时通常在10秒以内。
方案2:有序采样优化方案(适用于tSample为升序排列的场景)
如果你的采样时间tSample是按时间递增排列的(绝大多数采样场景都符合这个特征),可以用numpy的二分查找实现更高性能,耗时仅为方案1的1/3左右:
import numpy as np starts = dfFixations['tStart'].values ends = dfFixations['tEnd'].values # 构造事件点:区间起始点标记为+1(进入注视区间),区间结束+1位置标记为-1(离开注视区间,适配闭区间规则) events = np.concatenate([starts, ends + 1]) deltas = np.concatenate([np.ones_like(starts), -np.ones_like(ends)]) # 按事件时间排序并计算累计注视状态 sorted_idx = events.argsort() sorted_events = events[sorted_idx] cum_fix_state = np.cumsum(deltas[sorted_idx]) # 去重事件点,保留每个时间点最终的注视状态 unique_events, unique_pos = np.unique(sorted_events, return_index=True) unique_state = cum_fix_state[unique_pos - 1] unique_state[0] = cum_fix_state[0] # 二分查找每个采样点对应的状态位置 sample_ts = dfSamples['tSample'].values pos = np.searchsorted(unique_events, sample_ts, side='right') - 1 is_fix = (pos >= 0) & (unique_state[pos] > 0) dfSamples['labels'] = np.where(is_fix, 'fixation', 'no_fixation')
你之前改造失败的原因
map/np.vectorize本质是按位置配对两个数组的元素进行计算,而你的dfFixations和dfSamples长度不同,无法一一对应,自然得不到正确结果。
内容的提问来源于stack exchange,提问作者heldm
相关产品推荐
相关产品推荐

