合并Pandas DataFrame自关联时如何避免内存问题?
按ID循环处理解决内存溢出问题
原方案通过全量merge生成中间DataFrame m,当数据规模为12000个ID、每个ID1000+条记录时,会产生百亿级别的中间数据,直接触发内存错误:
MemoryError: Unable to allocate 39.6 GiB for an array with shape (5309349043, ) and data type int64
按ID循环处理完全可行,且能大幅降低内存占用——每次仅处理单个ID的子数据集,不会生成超大规模的中间表。
实现步骤与代码
基础循环实现
import pandas as pd # 确保日期列格式正确 df['Date'] = pd.to_datetime(df['Date']) # 初始化结果列 df['dates_between'] = 0 # 按ID分组循环处理 for id_val, group in df.groupby('ID'): # 复制分组数据,避免修改原数据集 sub_df = group.copy().reset_index(drop=True) # 计算每个记录的日期范围起始点(此处为6个月偏移,按需调整) sub_df['Begin'] = sub_df['Date'] - pd.DateOffset(months=6) # 仅在当前ID的子数据集中执行自关联 merged = sub_df.reset_index().merge(sub_df[['Date']].reset_index(), how='cross') # 判断日期是否在目标范围内 merged['to_count'] = (merged['Date_x'] >= merged['Date_y']) & (merged['Begin'] <= merged['Date_y']) # 统计每个行的符合条件记录数 count_result = merged.groupby('index_x')['to_count'].sum() # 将结果回填到原DataFrame对应行 df.loc[df['ID'] == id_val, 'dates_between'] = count_result.values
更高效的优化方案(二分查找)
如果每个ID的记录数较多,推荐用searchsorted替代merge,时间复杂度从O(n²)降至O(n log n),内存占用进一步降低:
import pandas as pd df['Date'] = pd.to_datetime(df['Date']) df['dates_between'] = 0 for id_val, group in df.groupby('ID'): # 对当前ID的记录按日期排序 sorted_group = group.sort_values('Date').copy() date_array = sorted_group['Date'].values # 计算每个记录的日期范围起始点 sorted_group['Begin'] = sorted_group['Date'] - pd.DateOffset(months=6) # 用二分查找快速定位范围边界 left_idx = sorted_group['Begin'].searchsorted(date_array, side='left') right_idx = sorted_group['Date'].searchsorted(date_array, side='right') # 计算符合条件的记录数 sorted_group['dates_between'] = right_idx - left_idx # 将结果回填到原DataFrame df.loc[df['ID'] == id_val, 'dates_between'] = sorted_group['dates_between'].values
内容的提问来源于stack exchange,提问作者Misha
相关产品推荐
相关产品推荐

