You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何统计CSV/Parquet唯一行?求优于HashMap或逐行遍历的算法

统计CSV/Parquet文件唯一行的方法

针对CSV文件

命令行工具(快速轻量)

  • 用awk直接去重并输出:
    awk '!seen[$0]++' input.csv > unique_output.csv
    
    原理是用内置数组seen记录每行是否出现过,只输出首次出现的行,小文件下速度快,内存占用取决于唯一行数量。
  • 用sort结合uniq:
    sort input.csv | uniq > unique_output.csv
    
    先排序再去重,适合内存不足但磁盘空间充足的场景,缺点是排序耗时较长。

代码实现(灵活可控)

Python中用Pandas处理,大文件需分块读取:

import pandas as pd

# 分块读取CSV,每块10万行
chunk_iter = pd.read_csv('input.csv', chunksize=100000)
unique_dfs = []

for chunk in chunk_iter:
    # 块内去重
    unique_chunk = chunk.drop_duplicates()
    unique_dfs.append(unique_chunk)

# 合并所有块并最终去重
final_unique = pd.concat(unique_dfs).drop_duplicates()
final_unique.to_csv('unique_output.csv', index=False)

针对Parquet文件

Parquet是列式存储,优先利用其特性减少IO开销:

分布式工具(大文件首选)

用Spark处理,天然支持分布式去重:

// Scala示例
val df = spark.read.parquet("input.parquet")
val uniqueDf = df.dropDuplicates()
uniqueDf.write.parquet("unique_output.parquet")

Spark会自动将数据分片到集群节点并行处理,无需手动管理内存。

单机代码实现

用PyArrow高效读取并去重:

import pyarrow.parquet as pq

table = pq.read_table('input.parquet')
df = table.to_pandas()
unique_df = df.drop_duplicates()
pq.write_table(pq.Table.from_pandas(unique_df), 'unique_output.parquet')

如果文件过大,可指定读取的列或分块处理。


大文件场景下的优化方案

当文件大到单机内存无法容纳所有唯一行时,以下方法比单纯的HashMap或逐行遍历更高效:

1. 哈希分治(精确去重)

核心思路是将大文件拆分多个小文件,保证相同的行进入同一个小文件,再逐个处理小文件:

  1. 遍历原文件,对每行计算哈希值,用哈希值 % N(N为小文件数量)将行写入对应编号的小文件;
  2. 对每个小文件单独用HashMap/awk去重,得到每个小文件的唯一行;
  3. 合并所有小文件的唯一行(无需再次去重,因为相同行已在同一个小文件中处理)。
    这种方法把内存压力分散到多个小文件,适合单机处理TB级文件,N的取值可根据内存大小调整(比如内存能容纳100万行,就把N设为总行数/100万)。

2. 利用列式存储特性(Parquet专属)

Parquet的列式存储天然适合批量处理重复值:

  • 优先过滤低基数列:如果某列重复率极高(比如状态列只有"成功"/"失败"),可先按该列分组,再在组内去重,减少后续处理的数据量;
  • 用列式引擎的批量去重:比如PyArrow或Spark的Parquet reader会批量读取列数据,内部优化了重复值的判断逻辑,比逐行遍历更高效。

3. 近似统计(无需精确结果)

如果只需要唯一行的数量估算而非具体行内容,用HyperLogLog算法:

  • 该算法只需KB级内存就能估算海量数据的唯一值数量,误差率低于2%;
  • Python中可使用hyperloglog库实现:
    from hyperloglog import HyperLogLog
    import csv
    
    hll = HyperLogLog(0.01)  # 误差率1%
    
    with open('input.csv', 'r') as f:
        reader = csv.reader(f)
        for row in reader:
            hll.add(','.join(row))
    
    print(f"估算唯一行数量: {len(hll)}")
    
    适合快速统计规模极大的文件,无需存储任何行数据。

内容的提问来源于stack exchange,提问作者hololensen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 21:27:11