处理两个大型Pandas DataFrame去重效率低下,求更优解决方案
高效移除大DataFrame中重复phone行的优化方案
你当前的嵌套循环方案时间复杂度是O(M*N)(650万 × 10万 = 6.5e12次操作),属于低效的暴力匹配,必然耗时极长。以下是几种远优于嵌套循环的解决方案,覆盖Pandas、NumPy、数据库等多种场景:
一、Pandas内置向量化方法(最简洁高效)
利用Pandas的isin()方法结合集合查询,集合的成员查询是O(1)时间复杂度,整体时间复杂度降到O(M+N):
dfll = df.loc[df['Cell'] == 'N'].copy().reset_index(drop=True) wdnc = pd.read_fwf(path, names=['phone']) # 将wdnc的phone转为集合,大幅提升查询效率 excluded_phones = set(wdnc['phone']) # 筛选出phone不在排除列表中的行 dfll_filtered = dfll[~dfll['phone'].isin(excluded_phones)] # 统计移除数量 removed_count = len(dfll) - len(dfll_filtered) print(f'Cases removed: {removed_count}')
如果担心内存占用,也可以直接传入wdnc['phone']到isin()中,Pandas内部会做优化,但转集合对超大样本的查询速度提升更明显。
二、NumPy向量化操作(性能接近Pandas,适合纯数值场景)
NumPy的in1d()函数底层基于C实现,能快速生成匹配掩码,速度极快:
import numpy as np dfll = df.loc[df['Cell'] == 'N'].copy().reset_index(drop=True) wdnc = pd.read_fwf(path, names=['phone']) # 转为NumPy数组 wdnc_arr = wdnc['phone'].to_numpy() dfll_arr = dfll['phone'].to_numpy() # 生成掩码:标记phone不在wdnc中的行 mask = ~np.in1d(dfll_arr, wdnc_arr) dfll_filtered = dfll[mask] removed_count = len(dfll) - len(dfll_filtered) print(f'Cases removed: {removed_count}')
三、数据库工具(适合内存不足以加载全量数据的场景)
如果650万行的wdnc占用内存过高,可以用SQLite临时数据库,利用数据库的索引优化查询:
import sqlite3 import pandas as pd dfll = df.loc[df['Cell'] == 'N'].copy().reset_index(drop=True) chunk_size = 100000 # 创建内存中的SQLite数据库 conn = sqlite3.connect(':memory:') # 导入dfll到临时表 dfll.to_sql('dfll_table', conn, index=False) # 分块导入wdnc到临时表,避免一次性加载内存 for chunk in pd.read_fwf(path, names=['phone'], chunksize=chunk_size): chunk.to_sql('wdnc_table', conn, index=False, if_exists='append') # 创建索引加速查询 conn.execute('CREATE INDEX idx_phone ON wdnc_table(phone);') # 执行筛选查询 query = """ SELECT * FROM dfll_table WHERE phone NOT IN (SELECT phone FROM wdnc_table) """ dfll_filtered = pd.read_sql(query, conn) removed_count = len(dfll) - len(dfll_filtered) print(f'Cases removed: {removed_count}') conn.close()
四、分块处理(极端内存不足时的备选方案)
如果连集合都无法完全加载到内存,可以分块读取wdnc,逐步累积排除的phone集合:
dfll = df.loc[df['Cell'] == 'N'].copy().reset_index(drop=True) chunk_size = 50000 excluded_phones = set() # 分块读取wdnc,逐步添加到排除集合 for chunk in pd.read_fwf(path, names=['phone'], chunksize=chunk_size): excluded_phones.update(chunk['phone'].tolist()) # 最终筛选 dfll_filtered = dfll[~dfll['phone'].isin(excluded_phones)] removed_count = len(dfll) - len(dfll_filtered) print(f'Cases removed: {removed_count}')
这些方案的核心思路都是避免暴力循环,利用哈希查询、向量化操作或数据库索引将时间复杂度从O(M*N)降到O(M+N),性能提升几个数量级。
内容的提问来源于stack exchange,提问作者MotoMatt5040
相关产品推荐
相关产品推荐

