python - 如何快速比较两个文本文件并获得唯一的行?

标签 python pandas dask vaex

我有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比较操作,其中nm是两个数据帧的长度。
另外,您的描述和代码之间也存在不一致的地方:

  • “也就是说,您需要一个csv或txt文件,其行位于第二个文件中,而不在第一个文件中。” ⟶这表示在dv_check中,但在dv_base中不是
  • dv_check.join(dv_base, on='data', how='inner', inplace=True)⟶这意味着dv_checkdv_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/

    相关文章:

    python - 使用 Dask 从 postgresql 导入数据

    python - Numpy where 函数相当于 pandas

    python - 查找长字符串中给定单词之前的\n 数量

    python - 迭代 Pandas 列并在每次迭代中计算新列

    dask - 当文件无法从本地计算机访问时使用 dask.dataframe 读取

    python - 使用 numpy.select 避免 div/0 错误

    python-2.7 - Pandas 无法比较未过时的日期和可感知过的日期时间

    python - 在服务器中更改 Django 的数据库结构

    python - 如何计算 Django 连接表中的对象数量?

    python - 是否可以根据批处理标签(y_true)分布更新每批处理的学习率?