【问题标题】:Python - suggestions for filtering/sorting a large file?Python - 过滤/排序大文件的建议?
【发布时间】:2011-08-10 20:51:35
【问题描述】:

我有一个包含 ~2000 万行 (~1.5GB) 的文件。每一行的格式为:

entry_1 entry_2 entry_3 ......... entry_5

该文件包含重复文件,但格式为:

entry_2 entry_1 entry_3 ......... entry_5

有些行的内容是相同的,但前两个元素经常(可能总是)交换。

有人对如何从这种大小的文件中删除这种性质的重复项有任何建议吗?

谢谢。

【问题讨论】:

  • 你有什么理由需要使用 python 吗?从 shell 来看,它非常简单且更高效 - 只需使用 head、tail 和 sort。
  • 行的顺序重要吗?
  • 那么你怎么知道entry_1和antry_2是否被交换了呢?并且您是否需要在正确订购这两个之后删除所有重复项?如果是这样,我建议在 python 中使用 1 pass 来修复 entry1/2,然后在命令行上使用 sort -u
  • 是只有entry_1和entry_2可以互换还是可以说entry_1和entry_5也可以互换。
  • 行的顺序不重要,只能交换entry_1和entry_2。

标签: python sorting filter


【解决方案1】:

一个合适的解决方案取决于您有什么限制以及您需要多久运行一次此操作。

如果这是一次性(或不经常)操作,并且内存使用不是一个大问题,那么这样的操作就足够了:

visited = set() # use set for faster lookups
with open(out_filename, "w") as outfile:
    with open(in_filename, "r") as infile:
        for line in infile:
            x = line.split()
            k = (tuple(sorted(x[:2])), tuple(x[2:]))
            if k not in visited:
                outfile.write(line)
                visited.add(k)

内存使用取决于我们需要在visited 中跟踪的唯一 条目的数量。如果重复的次数不多,那么您最终会得到内存中的几乎所有数据。

如果内存使用成为问题,您可以分多个阶段执行此操作:

  1. 首先通过对每行中的前 2 个元素进行排序来预处理文件。
  2. 按行对整个文件进行排序
  3. 现在可以直接删除重复项,因为重复项会一起出现。

第 2 步和第 3 步可以合并,因为您可以在执行排序时比较条目时简单地丢弃重复项。

如果您不介意使用 shell,可以使用sort -u yourfile 完成第 2 步和第 3 步。

请注意,这会更改文件中行的顺序(您提到的不是问题)。

要以牺牲一些性能为代价大幅减少内存使用量,您可以使用基于文件的数据库来存储和查找访问过的条目(代替 set())。

您可以通过在内存中存储条目的哈希来加快此速度,并且仅在哈希匹配时查询数据库以确认条目是否确实相同。哈希可以简单到获取每个条目的第一个字符,或者使用内置的hash() 函数,或者选择existing hash algorithm。每种方法都是性能、散列大小和冲突频率之间的折衷。一个好的选择将取决于您的数据和您的限制。

这需要一些努力才能找到最佳解决方案。仅当您需要经常执行此操作时才值得着手。

【讨论】:

    【解决方案2】:
    separator = " "
    aSet = set()
    with open('myfile', 'rU') as infile:
        for line in infile:
            tempLine = line.split(separator)
            tempLine = tempLine[1:2] + tempLine[0:1] + tempLine[2:]
            tempLine = separator.join(tempLine)
            if line not in aSet and tempLine not in aSet:
                aSet.add(line)
    

    现在,aSet 包含唯一的行列表,无论 entry_1entry_2 是否已交换。

    编辑:如果所有条目都可以交换并且该行仍然被认为是唯一的,那么:

    separator = " "
    aSet = set()
    with open('myfile', 'rU') as infile:
        for line in infile:
            aSet.add(frozenset(line.split(separator)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-03
      • 1970-01-01
      • 2010-12-25
      • 1970-01-01
      • 2021-11-05
      • 2012-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多