Python读取一个大文件并消除重复行

Python读取一个大文件并消除重复行,python,large-files,Python,Large Files,我有一个巨大的文本文件,其中有重复的行。规模约为15000000行。我想找到最有效的方法来读入这些行并消除重复。我正在考虑的一些方法如下:- 读入整个文件,做一个列表(设置(行)) 一次读入10k行,列出(设置(行)),在列表中再读入10k行,列出(设置(行))。重复一遍 你将如何处理这个问题?任何形式的多处理都会有帮助吗?多处理不会真正有帮助,因为内存是瓶颈。您将需要使用哈希: 读线 计算散列,例如md5,在一组遇到的所有散列中查找它 如果在集合中未找到哈希,则输出行,并将此哈希添加到集合中

我有一个巨大的文本文件,其中有重复的行。规模约为15000000行。我想找到最有效的方法来读入这些行并消除重复。我正在考虑的一些方法如下:-

  • 读入整个文件,做一个列表(设置(行))
  • 一次读入10k行,列出(设置(行)),在列表中再读入10k行,列出(设置(行))。重复一遍

  • 你将如何处理这个问题?任何形式的多处理都会有帮助吗?

    多处理不会真正有帮助,因为内存是瓶颈。您将需要使用哈希:

  • 读线
  • 计算散列,例如md5,在一组遇到的所有散列中查找它
  • 如果在集合中未找到哈希,则输出行,并将此哈希添加到集合中 需要注意的几件事:

    • md5占用128位,因此即使没有开销,它的ram也超过2G
    • set和dict的内存开销很大
    因此,如果你有4+演出,这是可行的。一个更具可扩展性的解决方案是将遇到的哈希值存储在磁盘上的已排序文件中,并每次搜索它们。这将是(很多!)慢,但你可以有你想要的低内存占用


    另外,如果您不关心结果文件中的行顺序,您可以根据一些散列函数(md5以a开头的行,md5以b开头的行等)将文件拆分为较小的文件。这将使它们足够小,只需对它们进行
    排序| uniq
    即可(如果愿意,也可以使用python在内存中进行排序)并连接结果。

    这里的内存是问题所在,因此可能无法将整个文件加载到内存中

    由于不需要维护行的顺序,一个可能的选择是执行某种基数排序:

    for each line in file:
        put this line into a new file based on the first character
    
    新文件现在应该小一些,如果某些文件仍然太大(例如,原始文件中的每一行都以
    a
    开头),您可以根据第2、第3等字符递归分割文件

    一旦这些文件足够小,可以放入内存,您就可以执行
    列表(set(list))
    方法,然后在完成后将文件重新组合在一起。或者,如果您可以使用
    uniq
    UNIX命令行工具,也可以使用它

    请注意,基数排序部分可以很容易地并行化,因为每一行都独立于其他行。

    请考虑是否真的需要在python中解决这个问题。你可以

    • 调出
      sort
      uniq
      ,这是大多数posix系统上的标准工具。他们将完成这项工作,速度更快,并在您考虑之前解决边缘问题(如内存不足)
    • 最简单的解决方案可能是使用
      sqlite
      -包创建一个内存中的数据库,将所有行插入一个临时表,并从中执行
      选择distinct…
      。同样,sqlite的性能比纯python要好

    文件是否已排序?每行是否有固定数量的字符?每行大约有多少个字符?您不关心行的当前顺序吗?因为使用set很可能会把它们搞砸。你的两种方法指向同一件事,在这种情况下,
    set()
    在比较字符串成本
    O(mn)
    时不会起任何作用,而且当你使用大约
    15000000
    行时,我想这种方法似乎不可行。@tommy.carstensen文件没有排序。每行的字符数各不相同~每行13-20个字符。重复行的百分比有多大?超过50%?低于1%?如果有很大一部分行是重复的,我会分而治之。这些行平均有13-20个字符,所以我想不需要计算md5(128位)?不需要,或者可以使用更短的散列,例如python的hash()函数并节省内存。我不确定它有多好。@tommy.carstensen我想有,因为总行数是
    15000000
    ,在如此大的数据集上匹配字符串会花费很多时间,我想这种哈希方法比
    set()
    好。我喜欢这种哈希方法。问题是如何处理哈希冲突。可以有两个不同的字符串,但其哈希相同。我不知道默认的散列函数有多好,所以按照@letitbee的建议使用md5可能更好。我认为可以截断sha1,仍然可以得到很好的熵。但由于输入集如此之大,我不知道这是一个多么好的主意。不,sqlite会让它变得更糟,而不是更好。实际上,您可以使用一个常规的、基于磁盘的数据库来实现这一点,但它的效率非常低,而且这并不能解决问题,而是让其他人来解决它。