【问题标题】:Faster way to remove duplicates from a very large text file in Python?从 Python 中非常大的文本文件中删除重复项的更快方法?
【发布时间】:2017-05-06 03:41:46
【问题描述】:

我有一个非常大的文本文件,其中包含要消除的重复条目。我不关心条目的顺序,因为文件稍后会被排序。

这是我目前所拥有的:

unique_lines = set()
outfile = open("UniqueMasterList.txt", "w", encoding = "latin-1")

with open("MasterList.txt", "r", encoding = "latin-1") as infile:
    for line in infile:
        if line not in unique_lines:
            outfile.write(line)
            unique_lines.add(line)

outfile.close()

已经运行了 30 分钟,还没有结束。我需要它更快。 在 Python 中有什么更快的方法?

【问题讨论】:

  • 我只会使用sort -u -o UniqueMasterList.txt MasterList.txt 而不是编写任何自定义代码。
  • 为什么不先排序呢?那么删除重复项就很容易了。
  • 与您的问题无关,但您无需关闭infile,因为您使用with 关键字打开它。
  • 当你说“非常大的文件”时,有多大?它有可能适合记忆吗?我想是这样,因为如果不是,set 会变得太大。如果您运行的是 64 位版本的 Python,它可能会进行交换,这肯定会使其太慢。

标签: python python-3.x text duplicates


【解决方案1】:

查找相应的系统命令。在Linux/UNIX,你会使用

uniq MasterList.txt > UniqueMasterList.txt

操作系统通常知道做这些事情的最佳方式。


评论后编辑

@Mark Ransom 提醒我 uniq 依赖于文件中连续的匹配行。实现这一点的最简单方法是对文件进行排序:

sort MasterList.txt | uniq > UniqueMasterList.txt

【讨论】:

  • 为什么更快?而且(我编辑了标题以使其更清晰),有没有更快的方法来做到这一点,但在 Python 中?
  • 它更快,因为操作系统可以优化其文件结构、存储和访问方法。通过从 Python 脚本调用系统命令,您可以在 Python 中更快地完成此操作。第二种选择可能是对行进行散列以加快 in 运算符的速度。要对此进行测试,请将它们插入集合而不是列表中,然后查看您获得的性能变化。
  • @Prune 原来的问题已经使用了set。使用加密哈希代替原始行字符串可能会减少数据负载,但它是否会更快是一个悬而未决的问题。
  • P.S. uniq 仅在数据已经排序时有效,否则您必须将其与 sort 配对。如果不这样做,它会非常快但不正确。
  • sort 命令也可用于直接使用标志u 删除重复项。如果您在多核系统上运行代码,它还可以利用多个内核,例如sort --parallel=4 -u file-with-duplicates.csv > file-no-duplicates.tsv.
【解决方案2】:

在 Python 中使用与 uniq 相同的技术:

import itertools
with open("MasterList.txt", "r", encoding = "latin-1") as infile:
    sorted_file = sorted(infile.readlines())
for line, _ in itertools.groupby(sorted_file):
    outfile.write(line)

这假定整个文件将适合内存,两次。或者文件已经排序,您可以跳过该步骤。

【讨论】:

    【解决方案3】:

    我建议的简单方法是使用散列和散列表。您可以使用有效的散列函数对每一行进行散列,然后将其插入到散列表中并输出计数为 1 的内容。类似于求解单词/字母使用哈希表的计数问题。查找只需 o(1) 成本,并且内存的使用量可以限制为一个常数,具体取决于所使用的哈希表的大小。

    【讨论】:

      【解决方案4】:
      SPLIT_COUNT = 30
      
      
      def write_data(t_file, value):
          t_file.write(value)
      
      
      def calculate_hash(filename, handle_file):
      
          with open(filename, 'r') as f:
      
              for line in f:
      
                  write_data(handle_file[hash(line)%SPLIT_COUNT], line)
      
      
      def generate_file(dir):
      
          handle_file, files = [], []
      
          for i in range(SPLIT_COUNT):
      
              path = dir+"split_"+str(i)
      
              files.append(path)
      
              f = open(path, 'w')
      
              handle_file.append(f)
      
          return files, handle_file
      
      
      def close_file(handle_file):
      
          for i in range(len(handle_file)):
      
              handle_file[i].close()
      
      
      def data_uniq(files, new_file):
      
          dataset = dict()
      
          n_file = open(new_file, 'w')
      
          for filename in files:
      
              f = open(filename, 'r')
      
              for line in f:
      
                  dataset[line] = 1
      
              f.close()
      
              for key in dataset.keys():
      
                  n_file.write(key)
      
              dataset = {}
      
          n_file.close()
      
      
      if __name__ == "__main__":
          filename = './clean.txt'
          generate_dir = './tmp/'
          new_file = './out.txt'
          files, handle_file = generate_file(generate_dir)
          calculate_hash(filename, handle_file)
          close_file(handle_file)
          data_uniq(files, new_file)
      

      【讨论】:

        猜你喜欢
        • 2011-04-14
        • 1970-01-01
        • 2015-01-01
        • 2012-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-27
        相关资源
        最近更新 更多