我有2个文本文件(* .txt),其中包含以下格式的唯一字符串:
udtvbacfbbxfdffzpwsqzxyznecbqxgebuudzgzn:refmfxaawuuilznjrxuogrjqhlmhslkmprdxbascpoxda
ltswbjfsnejkaxyzwyjyfggjynndwkivegqdarjg:qyktyzugbgclpovyvmgtkihxqisuawesmcvsjzukcbrzi
第一个文件包含 5000万个这样的行(4.3 GB),第二个文件包含 100万个这样的行(112 MB)。一行包含40个字符,定界符:和另外45个字符。任务:获得两个文件的唯一值。 也就是说,您需要一个 csv或txt 文件,该文件的行位于第二个文件中,而不在第一个文件中。
我正在尝试使用 vaex (Vaex)执行此操作:
import vaex
base_files = ['file1.txt']
for i, txt_file in enumerate(base_files, 1):
for j, dv in enumerate(vaex.from_csv(txt_file, chunk_size=5_000_000, names=['data']), 1):
dv.export_hdf5(f'hdf5_base/base_{i:02}_{j:02}.hdf5')
check_files = ['file2.txt']
for i, txt_file in enumerate(check_files, 1):
for j, dv in enumerate(vaex.from_csv(txt_file, chunk_size=5_000_000, names=['data']), 1):
dv.export_hdf5(f'hdf5_check/check_{i:02}_{j:02}.hdf5')
dv_base = vaex.open('hdf5_base/*.hdf5')
dv_check = vaex.open('hdf5_check/*.hdf5')
dv_result = dv_check.join(dv_base, on='data', how='inner', inplace=True)
dv_result.export(path='result.csv')
结果,我得到了具有唯一行值的 result.csv 文件。但是验证过程需要很长时间。此外,它使用所有可用的RAM和所有处理器资源。 如何加快此过程?我究竟做错了什么?有什么可以做得更好的?值得使用其他库(pandas,dask)进行检查吗,它们会更快吗? UPD 10.11.2020
到目前为止,我还没有找到比以下选项更快的方法:
from io import StringIO
def read_lines(filename):
handle = StringIO(filename)
for line in handle:
yield line.rstrip('\n')
def read_in_chunks(file_obj, chunk_size=10485760):
while True:
data = file_obj.read(chunk_size)
if not data:
break
yield data
file_check = open('check.txt', 'r', errors='ignore').read()
check_set = {elem for elem in read_lines(file_check)}
with open(file='base.txt', mode='r', errors='ignore') as file_base:
for idx, chunk in enumerate(read_in_chunks(file_base), 1):
print(f'Checked [{idx}0 Mb]')
for elem in read_lines(chunk):
if elem in check_set:
check_set.remove(elem)
print(f'Unique rows: [{len(check_set)}]')
UPD 11.11.2020:感谢@ m9_psy提供提高性能的提示。真的更快!当前,最快的方法是:
from io import BytesIO
check_set = {elem for elem in BytesIO(open('check.txt', 'rb').read())}
with open('base.txt', 'rb') as file_base:
for line in file_base:
if line in check_set:
check_set.remove(line)
print(f'Unique rows: [{len(check_set)}]')
是否可以进一步加快此过程?
最佳答案
我怀疑join
操作需要n * m
比较操作,其中n
和m
是两个数据帧的长度。
另外,您的描述和代码之间也存在不一致的地方:
dv_check
中,但在dv_base
中不是dv_check.join(dv_base, on='data', how='inner', inplace=True)
⟶这意味着dv_check
和dv_base
中的无论如何,一个想法是使用
set
,因为检查集合中的成员资格具有O(1)
的时间复杂性,而检查列表中的成员资格具有O(n)
的复杂性。如果您熟悉SQL世界,这等效于从LOOP JOIN策略过渡到HASH JOIN策略:# This will take care of removing the duplicates
base_set = set(dv_base['data'])
check_set = set(dv_check['data'])
# In `dv_check` but not `dv_base`
keys = check_set - base_set
# In both `dv_check` and `dv_base`
keys = check_set & base_set
这只会给您满足您条件的键。您仍然必须过滤两个数据框以获取其他属性。我在配备16GB RAM的2014 iMac上用1分14秒完成了任务。
关于python - 如何快速比较两个文本文件并获得唯一的行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64630398/