删除非常大的数据集上的重复项

Posted

技术标签:

【中文标题】删除非常大的数据集上的重复项【英文标题】:Removing duplicates on very large datasets 【发布时间】:2019-02-23 17:22:05 【问题描述】:

我正在处理一个 13.9 GB 的 csv 文件,其中包含大约 1600 万行和 85 列。我知道可能有几十万行是重复的。我运行了这段代码来删除它们

import pandas

concatDf=pandas.read_csv("C:\\OUT\\Concat EPC3.csv")
nodupl=concatDf.drop_duplicates()
nodupl.to_csv("C:\\OUT\\Concat EPC3- NoDupl.csv",index=0)
low_memory=False  

但是,这让我陷入了 MemoryError。我的内存是 16GB,不能再高了。有没有一种更有效的方法来删除重复项,可能无需我将 csv 文件分解成更小的文件,就可以将其分块?

【问题讨论】:

"Large data" work flows using pandas的可能重复 dask 可能会给你带来一些运气 如果你有 Linux,这很好用:cat Concat\ EPC3.csv |排序 | uniq(如果有,请注意标题) 在这种情况下对 df 进行分块将是有效的,因为它会删除块中出现的重复项,但如果重复出现在多个块中,它们将不会被删除(只是块中的重复项将被删除) )。 我建议做的一件事是查看是否可以通过指定每列的 dtype 来减少 DF 的内存。例如,pandas 尝试预先猜测数据类型。有时您认为列可能是纯类型 Int 或 float,但 Pandas 可能会将其分配为对象,或者可能存在重复的列是可以分配类别的对象。 Obj 到 Float 或 int 的转换大大减少了内存,对象到类别也是如此。 【参考方案1】:

最简单的解决方案是为文件中的每一行创建一个哈希表——在你的工作内存中存储 16M 哈希应该不是问题(取决于哈希大小)——然后你可以再次迭代你的文件并确保您只记下每个哈希的一次出现。您甚至不需要解析 CSV,也不需要 Pandas。

import hashlib

with open("input.csv", "r") as f_in, \
        open("output.csv", "w") as f_out:
    seen = set()  # a set to hold our 'visited' lines
    for line in f_in:  # iterate over the input file line by line
        line_hash = hashlib.md5(line.encode()).digest()  # hash the value
        if line_hash not in seen:  # we're seeing this line for the first time
            seen.add(line_hash)  # add it to the hash table
            f_out.write(line)  # write the line to the output

这使用 MD5 作为哈希,因此每行大约需要 16B + 设置开销,但这仍然远远低于将所有内容存储在内存中 - 对于 16M 行 CSV 文件,您可以预期约 500MB 的内存使用量。

【讨论】:

只循环一次输入行不是更有效吗? I/O 操作可能是最昂贵的。 就 CSV 而言,某些行可能是等效的,但散列到不同的值。例如 CSV 处理空格和引号。 @norok2 - 没错,我已经用单通道方法对其进行了更新。 @norok2 - 集合的查找速度(它们本身就是哈希表)比列表快得多,尤其是随着 seen 的大小增长。 @norok2 - 如果我们要计算操作,in set()O(1) 操作(哈希表查找),list.append()set.add() 也是 O(1),但需要注意的是集合需要更长的时间来处理(由于散列)以及底层系统可能需要更多操作作为列表和集合增长的事实(即不计算摊销复杂度)。同时,in list() 是一个O(n) 操作,当您向列表中添加更多元素时,它会线性变慢。除了非常非常小的列表之外,集合在此类任务中将总是优于它们。【参考方案2】:

UNIX 模拟器怎么样?

uniq <filename> >outputfile.txt

(类似的)

【讨论】:

uniq 仅在重复行彼此跟随时才有效(它会跳过与前一行相同的每一行)。因此,对于大多数应用程序,您需要先sort,然后再使用uniq。但如果您的 csv 文件中有带换行符的字符串,它通常不起作用。或者,如果您在 csv 文件中有索引(因为索引是唯一的)。而且您需要注意标题,以免对其进行排序。但如果这一切都很好,那么uniq 会非常快。并在 O(n) 中运行。【参考方案3】:

与zwer 的想法基本相同,但检查具有相同哈希的行中的相等性(而不是自动丢弃重复的哈希)。

file_in = "C:\\OUT\\Concat EPC3.csv"
file_out = "C:\\OUT\\Concat EPC3- NoDupl.csv"

with open(file_in, 'r') as f_in, open(file_out, 'w') as f_out:
    # Skip header
    next(f_in)
    # Find duplicated hashes
    hashes = set()
    hashes_dup = 
    for row in f_in:
        h = hash(row)
        if h in hashes:
            hashes_dup[h] = set()
        else:
            hashes.add(h)
    del hashes
    # Rewind file
    f_in.seek(0)
    # Copy header
    f_out.write(next(f_in))
    # Copy non repeated lines
    for row in f_in:
        h = hash(row)
        if h in hashes_dup:
            dups = hashes_dup[h]
            if row in dups:
                continue
            dups.add(row)
        f_out.write(next(f_in))

【讨论】:

以上是关于删除非常大的数据集上的重复项的主要内容,如果未能解决你的问题,请参考以下文章

在非常大的数据集中查找重复项 [重复]

不平衡数据集上的一类文本分类

大型数据集上的 R 中的矩阵数学

数据结构( Pyhon 语言描述 ) — —第11章:集和字典

pandas to_parquet 在大型数据集上失败

如何评估不同模型在一个数据集上的性能?