删除python中的重复行

时间:2015-07-06 21:59:35

标签: python python-2.7

我有以下表格的数据:

#@ <abc>
 <http://stackoverflow.com/questions/ask> <question> _:question1 .
#@ <def>
<The> <second> <http://line> .
#@ <ghi>
 _:question1 <http#responseCode> "200"^^<http://integer> .
#@ <klm>
<The> <second> <http://line1.xml> .
#@ <nop>
 _:question1 <date> "Mon, 23 Apr 2012 13:49:27 GMT" .
#@ <jkn>
<G> <http#fifth> "200"^^<http://integer> .
#@ <k93>
 _:question1 <http#responseCode> "200"^^<http://integer> .
#@ <k22>
<This> <third> <http://line2.xml> .
#@ <k73>
 <http://site1> <hasAddress> <http://addr1> .
#@ <i27>
<kd8> <fourth> <http://addr2.xml> .

现在每当两条线相等时,如: _:question1 <http#responseCode> "200"^^<http://integer> . ,那么我想删除相等的线(逐字符串相等的线是等号)以及(一世)。后续行(以终点结束)(ii)。等号之前的行(以#@开头)。

#@ <abc>
 <http://stackoverflow.com/questions/ask> <question> _:question1 .
#@ <def>
<The> <second> <http://line> .
#@ <nop>
 _:question1 <date> "Mon, 23 Apr 2012 13:49:27 GMT" .
#@ <jkn>
<G> <http#fifth> "200"^^<http://integer> .
#@ <k73>
 <http://site1> <hasAddress> <http://addr1> .
#@ <i27>
<kd8> <fourth> <http://addr2.xml> .

现在,一种方法是将所有这些行存储在python中的一个集合中,只要两行相等(即它们逐个字符匹配),就删除前一行和后两行。但是,我的数据集大小为100GB(我的RAM大小为64GB),因此我无法将这些信息保存在主内存中。有没有什么方法可以删除重复的行以及它们在python中的前两行,主存储空间有限(RAM大小为64 GB)

3 个答案:

答案 0 :(得分:2)

保留已经看到的行的哈希码的布尔哈希表。

对于每一行:

  • 如果行hash()与你已经看过的东西相符,你就有可能匹配:扫描文件以检查它是否真的重复。

  • 如果行hash()es为新哈希,则只需第一次标记哈希。

尽可能多地为此哈希表提供内存,误报率很低(即,您需要扫描重复项的次数较少,但没有找到)。

示例:

table_size = 2**16
seen = [False]*table_size
for line in file:
    h = hash(line) % table_size
    if seen[h]:
        dup = False
        with open('yourfile','r') as f:
            for line1 in f:
                if line == line1:
                    dup = True
                    break
            if not dup:
                print(line)
    else:
        seen[h] = True
        print(line)

正如已经指出的那样,由于你不能将所有行存储在内存中,你没有多少选项,但至少这个选项并不需要为每一行扫描文件,因为表中的大多数条目都是False,即如果tabe不满,则算法是次二次的;一旦桌子满了,它就会退化为O(n 2 )。

你可以创建一个非常节省内存的哈希表实现,每个哈希代码只需要1比特(例如,使它成为一个字节数组,每个字节可以存储8个布尔值)

有关更多高级技巧,另请参阅Bloom Filters

答案 1 :(得分:1)

一种相当简单的方法 - 制作数据版本,使每行包含一个带有行号的字段。使用unix“sort”对新文件进行排序,不包括行号字段。排序实用程序将合并排序文件,即使它超过可用内存的大小。现在您有一个新文件,其中订购了重复项以及它们的原始行号。提取重复项的行号,然后将其用作输入以线性处理原始数据。

更详细的步骤。

  • 制作文件的新版本,使每行都以其行号作为前缀。所以,“someline”变成“1,someline”
  • 使用unix排序实用程序对此文件进行排序 - sort -t“,” - k2,2 file
  • 在第二个字段中扫描新文件以查找连续的重复条目
  • 此类条目的行号(第一个字段)是原始文件中重复行的行号 - 提取这些行并将其用作输入以删除原始数据中的重复项。由于您确切知道它们的位置,因此无需读取整个文件或为重复项创建巨大的内存中结构

与其他一些建议相比,这种方法的优点是 - 无论输入的大小和可用内存的大小如何,它总是有效,并且由于散列冲突或其他概率伪像而不会失败。你正在利用unix排序中的合并排序,其中硬件 - 处理大于内存的输入 -  已经为你完成了。

答案 2 :(得分:1)

以下是使用UNIX sort / uniq:

进行操作的概述
  1. 修改数据格式,以便每条记录都是一行。您可以使用here方法执行此操作。

  2. 使用sort command对数据进行排序。请注意,您可以使用--key选项指定哪些字段很重要,您可能需要通过选择所有其他字段作为键来排除#@ <abc>部分(我不完全确定您的说明)。

  3. uniq command应用于已排序的输出,以仅获取唯一的行。

  4. 据我所知,这应该可以在核外数据上正常工作。