Pandas基于另一DataFrame双列条件过滤大数据集的实现方案
问题场景说明
现有两个DataFrame:
- dfA(规模10万行)存储每个用户对应的坐标区间,每个
Name对应唯一的区间记录 - dfB(规模4.4亿行)存储每个用户的位置点位记录
需要筛选同时满足Name匹配、且点位落在对应坐标区间内的记录,不能使用numpy广播方案(会触发内存溢出)
可行处理方案
以下两种方案均不会产生超大中间矩阵,内存占用可控:
方案1:字典映射+分块读取(内存占用最低,优先推荐)
该方案无需一次性加载全量dfB进内存,适合内存配置一般的场景:
- 先把dfA转换为查询字典,10万条数据的字典内存占用可以忽略:
# 构造{Name: (start_coordinate, end_coordinate, gender, ID)}的查询字典 name_info = dfA.set_index('Name').T.to_dict('tuple')
- 分块读取dfB,逐块筛选符合条件的记录:
import pandas as pd # 每次读取100万行,可根据自身内存调整chunksize大小 chunk_list = [] for chunk in pd.read_csv("dfB的文件路径.csv", chunksize=1000000): # 映射得到当前块每个Name对应的区间等信息,无匹配的会返回NaN直接过滤 chunk[['start_coordinate', 'end_coordinate', 'gender', 'ID']] = chunk['Name'].map(name_info).apply(pd.Series) # 筛选position落在区间内的记录 valid_chunk = chunk[(chunk['position'] >= chunk['start_coordinate']) & (chunk['position'] <= chunk['end_coordinate'])] chunk_list.append(valid_chunk) # 合并所有符合条件的块 total_valid = pd.concat(chunk_list, ignore_index=True)
- 拆分得到最终结果:
# 提取new_dfB,保留原dfB的字段 new_dfB = total_valid[['Name', 'position', 'string']].drop_duplicates() # 提取new_dfA,保留原dfA的字段,去重 new_dfA = total_valid[['Name', 'gender', 'start_coordinate', 'end_coordinate', 'ID']].drop_duplicates()
方案2:按Name merge后过滤(适合内存足够容纳全量dfB的场景,速度更快)
如果你的服务器内存足够放下全量dfB(4.4亿行10列的话大概需要几十G内存,根据实际字段类型调整),可以直接用merge操作,逻辑更简单:
# 按Name做内连接,只保留两边都存在的Name对应的记录 df_merged = pd.merge(dfB, dfA, on='Name', how='inner') # 过滤position落在区间内的记录 df_valid = df_merged[(df_merged['position'] >= df_merged['start_coordinate']) & (df_merged['position'] <= df_merged['end_coordinate'])] # 拆分结果 new_dfB = df_valid[dfB.columns].drop_duplicates() new_dfA = df_valid[dfA.columns].drop_duplicates()
方案原理说明
两种方案都规避了numpy广播产生的10万 * 4.4亿超大中间矩阵,所有操作均基于行级匹配/过滤,内存占用最高只会等于你设置的分块大小或者全量dfB的大小,不会出现内存溢出问题。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

