Pandas大数据集优化:获取当前日期前最大日期的分数极值
Pandas 高效实现「获取当前日期前最大日期的Score极值」需求
我需要在Pandas DataFrame中,为每条数据找到当前testdate之前的最大日期,再获取该日期对应的score最大值与最小值,并将结果作为新列添加至DataFrame。现有代码可实现需求,但因数据集规模庞大,运行效率偏低,特寻求更高效的实现方案。
现有实现代码
版本1:分函数实现
def findMax(x): import numpy as np larger = frame.testdate[frame.testdate < x] if len(larger) != 0: return max(larger) else: return np.nan def scorerange(row): x=frame.loc[frame['testdate'] == row.PriorDate] return x.score.max(),x.score.min() import pandas as pd data = {'testdate' : ['2022-04-01', '2022-04-01', '2022-03-29', '2022-03-29','2022-03-27', '2022-03-27'], 'student' : ['Joe', 'Mary', 'Joe', 'Mary', 'Joe', 'Mary'], 'score' : [35, 45, 83,79,40,80]} frame = pd.DataFrame(data) frame.testdate=pd.to_datetime(frame.testdate) frame['PriorDate']=frame.testdate.apply(findMax) frame['resultmax'],frame['resultmin'] = zip(*frame.apply(scorerange, axis=1)) frame
版本2:单函数实现
def findall(x): import numpy as np larger = frame.testdate[frame.testdate < x] if len(larger) != 0: x=frame.loc[frame['testdate'] == max(larger)] return max(larger),x.score.max(),x.score.min() else: return np.nan,np.nan,np.nan frame['PriorDate'],frame['resultmax'],frame['resultmin'] = zip(*frame.testdate.apply(findall))
现有方案的效率问题
现有代码依赖apply逐行遍历,本质是Python层面的循环操作,时间复杂度为O(n²)——每次调用函数都要全表筛选日期,在大数据集下会导致严重的性能瓶颈。
高效实现方案
核心思路是通过预处理聚合+向量式映射替代逐行计算,利用Pandas内置的优化操作避免循环开销,时间复杂度降至O(n log n)(主要来自排序步骤)。
具体步骤与代码
- 按日期聚合Score极值:先计算每个日期对应的
score最大、最小值,生成日期-极值映射表 - 生成日期前序映射:对唯一日期排序后,通过
shift快速获取每个日期的前序最大日期 - 关联回原表:将日期映射与极值表合并,最终关联到原DataFrame
import pandas as pd import numpy as np # 1. 加载并预处理数据 data = { 'testdate': ['2022-04-01', '2022-04-01', '2022-03-29', '2022-03-29','2022-03-27', '2022-03-27'], 'student': ['Joe', 'Mary', 'Joe', 'Mary', 'Joe', 'Mary'], 'score': [35, 45, 83,79,40,80] } frame = pd.DataFrame(data) frame['testdate'] = pd.to_datetime(frame['testdate']) # 2. 按日期聚合score的最大、最小值 date_score_stats = frame.groupby('testdate')['score'].agg(['max', 'min']).reset_index() date_score_stats.columns = ['testdate', 'score_max', 'score_min'] # 3. 生成每个日期的前序最大日期映射 unique_dates = date_score_stats['testdate'].sort_values().reset_index(drop=True) date_mapping = pd.DataFrame({ 'testdate': unique_dates, 'PriorDate': unique_dates.shift(1) # 排序后shift(1)即为前一个最大日期 }) # 4. 合并映射表并关联回原DataFrame date_prior_stats = pd.merge( date_mapping, date_score_stats, left_on='PriorDate', right_on='testdate', how='left' ).drop(columns='testdate_y').rename(columns={ 'testdate_x': 'testdate', 'max': 'resultmax', 'min': 'resultmin' }) frame = pd.merge(frame, date_prior_stats, on='testdate', how='left')
方案优势
- 全部采用Pandas内置的向量化操作,避免Python循环的性能损耗
- 聚合与映射仅需几次全表扫描,而非逐行的重复筛选
- 适用于百万级甚至更大规模的数据集,性能提升显著
内容的提问来源于stack exchange,提问作者Stumbling Through Data Science
相关产品推荐
相关产品推荐

