如何通过出现次数删除两个大文本文件中的重复行?

问题描述 投票:0回答:2

我有两个大的文本文件,具有相同的行数(900万行,每个文件约12gb)。因此它们无法加载到内存中。

表中显示的这些文本文件中的行如下所示:

enter image description here

我需要删除A.txtB.txt中的重复项,仅保留最频繁的组合。如果出现2条最频繁的行且重复次数相同,则程序应选择首先出现在文本中的行,然后删除所有其他行。

在实际文件中,行不仅是(A,B,C,D,... 1,6,7,..),每行大约有2000个字符。

表中显示的最终文本文件应如下所示:

enter image description here

python sorting duplicates frequency
2个回答
1
投票

如何避免一次将2×12 GB读取到内存中,但仍然处理所有数据?

通过逐块加载这些24 GB的块,并丢弃您不再需要的数据。由于文件是基于行的,因此逐行读取和处理似乎是谨慎的做法。在现代个人计算机上,一次存储4000个字符的字符不会造成问题。

合并文件

您希望最终结果按A.txt的行内容排序(甚至排序)。为了在更改顺序时不丢失A.txtB.txt中各行之间的关系,我们需要首先组合其内容。

这样做

  • 打开两个文件而不阅读它们
  • 打开新文件AB.txt进行写入
  • 重复以下步骤,直到处理完A.txtB.txt为止:
    • 读取一行A.txt
    • 读取一行B.txt
    • 将合并的内容作为新行添加到AB.txt
    • 丢弃我们到目前为止从内存中读取的内容

[如果您知道某个字符(例如'\t')不能出现在A.txt中,则可以将其用作分隔符:

with \
        open("A.txt") as a_file, \
        open("B.txt") as b_file, \
        open("AB.txt", "w") as ab_file:
    for a_line, b_line in zip(a_file, b_file):
        # get rid of the line endings, whatever they are
        a_line, = a_line.splitlines()
        b_line, = b_line.splitlines()

        # output the combined content to AB.txt
        print(f"{a_line}\t{b_line}", file=ab_file)

((请注意,这取决于zip充当“惰性”并返回生成器,而不是像在Python 2中那样完全读取文件并返回庞大的列表。]

如果A.txt中的所有行都具有相同的固定长度,则根本不需要任何分隔符。 (不过,为了保持调试时的理智,您可能仍要使用其中一个。)如果您不知道A.txt中不会出现任何字符,则可以创建csv.writer并使用csv.writer将行写入its writerow method。它将为您处理所需的转义或引用。

您可能想知道步骤在哪里

丢弃我们到目前为止从内存中读取的内容

已实施。这在这里隐式地发生,因为对于每次迭代,仅保存文件中数据的变量writerowAB.txt被覆盖。

订购组合文件

为了订购整个文件,我们必须将其完全加载到内存中,对吧?

不。好吧,实际上是的,但是又一次,并不是全部。我们可以使用a_line。您可以尝试自己在Python中实现此功能,也可以只使用b_lineexternal sorting)来实现。在Linux或macOS系统上,您已经可以使用它。在Windows上,应将其包含在任何UNIX模拟器(例如Cygwin或MinGW)中。如果您已经使用Windows的默认Git安装程序安装了Git,则可以使用随附的“ Git Bash”中的UNIX UNIX command line tool sort

请注意,由于我们内容在每一行中的顺序,文件将首先按照来自sort的内容排序,然后(如果相同的话)按照来自manual page的内容排序。

计数

一旦您对组合文件进行了排序,就可以再次逐行处理它,但是必须在各行之间保留some数据。

我们想要做的是:

  • 对于具有相同A含量的后续行的每个块:
    • 在此内,对于具有相同B含量的后续行的每个块:
    • 计算其行数
    • 保持尚未见过的B内容(在A内容块内)的行数最多
    • 在A内容块的末尾:输出包含A内容和该A内容最频繁的B内容的行

因为我们可以依靠上面施加的顺序,所以会产生想要的结果。

类似这样的方法应该起作用:

  • 读一行
  • 分为A内容和B内容
  • 如果A内容与上一行相同*:
    • 如果B内容与上一行相同*:
      • 增加当前a-b含量组合的计数器
    • 其他(即,如果B含量与前一行不同):
      • 存储迄今为止最常看到的B内容及其理货
        • (它是以前最常看到的B内容,或者是前一行中的内容)
      • 重置当前a-b-content组合的计数器
      • 将该计数器加一(对于当前行)
      • 将B内容存储在某个位置,因此我们可以将其与下一次迭代中下一行的内容进行比较
  • 其他(即,如果A含量与前一行不同)**:
    • 输出前一行的A内容和前一行中最常见的B内容
    • 重置当前a-b-content组合的计数器
    • 重置有关最常显示的B含量及其相符的信息
    • 存储当前行的A内容和B内容,以便在下一次迭代中将它们与下一行的内容进行比较
  • 重复直到处理完整个文件

*第一行,隐式为sort

**到达文件末尾时也执行此操作

实际上是在Python中作为读者的练习者来实现的。请注意,您必须在上面的描述中提到它们的步骤之前定义一些使用的变量,以使其具有正确的作用域。


0
投票

此选项将不需要整个文件存储在内存中,但是将需要保留一个字典,其中A为键,而多个字典则以B为键。如果您可以对值进行哈希或分类(将int值分配给每个唯一A和每个唯一B),则可以简化此操作。

编辑:更改了字典以使用散列键来减少内存占用,但占用了CPU的开销,并且更改了输出以显示要保留的行(因为混淆了原始A和B值)

假设我的文件是:

A.txt
B.txt

用适当的结果存储替换打印。

© www.soinside.com 2019 - 2024. All rights reserved.