计算大型CSV文件列中的唯一值

6fe3ivhb  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(75)

我的代码读取CSV文件并计算其中的行数,以及每列中非空值和唯一值的数量。它可以很好地处理小文件,大小为几千兆字节。大于20 GB的文件会出现这个问题--接下来的每一百万行的处理速度越来越慢,然后就会出现内存不足的情况。
问题是代码处理内存中的唯一值,而内存不可能是无限的。文件的重量不仅可以达到20千兆字节,也可以达到200千兆字节。如何解决这一问题?

def read_csv(file_path, delimiter, encoding):

with open(file_path, encoding=encoding) as f:
    reader = csv.reader(f, delimiter=delimiter)
    header = next(reader)
    columns = {col_name: {'total': 0, 'not_null': 0, 'unique': 0, 'first_five': set()} for col_name in header}
    column_data = defaultdict(lambda: defaultdict(int))
    print('!')
    num = 0
    for row in reader:
        if num % 1000000 == 0:  
            print(num / 1000000, 'M rows')
        num+=1

        try:
            for col_index, col_value in enumerate(row):
                column_name = header[col_index]

                columns[column_name]['total'] += 1
                if col_value:
                    columns[column_name]['not_null'] += 1
                    column_data[column_name][col_value] += 1
                    if column_data[column_name][col_value] == 1:
                        columns[column_name]['unique'] += 1
                        if len(columns[column_name]['first_five']) < 5:
                            columns[column_name]['first_five'].add(col_value)
        except:
            print(row)
bkkx9g8r

bkkx9g8r1#

因为你是在计算唯一值,所以在将它们添加到字典/集合之前,你可能有更多的回旋余地来散列值。也许是这样的:

import csv
import hashlib
import json

with open("data.csv", "r", encoding="utf-8") as file_in:
    reader = csv.DictReader(file_in)

    column_metadata = {
        col_name: {
            'total': 0,
            'not_null': 0,
            'unique': set(),
            'first_five': list()
        }
        for col_name in reader.fieldnames
    }

    for index, row in enumerate(reader):
        if index % 10_000 == 0:
            print(f"rows so far: {index}", end="\r", flush=True)

        for key, value in row.items():
            if value is None:
                continue

            metadata = column_metadata[key]
            metadata["not_null"] += 1
            metadata["unique"].add(hashlib.sha256(value.encode()))
            if index <= 4:
                metadata["first_five"].append(value)

for key, value in column_metadata.items():
    value["total"] = index
    value["unique"] = len(value["unique"])
print()
print(json.dumps(column_metadata, indent=4))

如果你担心sha 256冲突,我认为hashlib也会支持sha 512。

相关问题