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

如何高效从数千个CSV提取指定两列唯一值构建Polars DataFrame

3000+TSV文件提取两列唯一值高效实现方案

你原有的逐个文件对比合并的实现,存在大量重复的全量DataFrame对比、内存释放操作,3000个文件的循环开销极高,且浪费了chr、pos列预排序的特性,下面提供两种更高性能的实现思路:


方案1:利用预排序特性的Polars原生实现

因为所有文件的chr、pos列已经预先排序,单个文件执行unique后仍会保持有序状态,不需要全量合并后再做全局散列去重,仅需做相邻对比即可完成全局去重,效率提升非常明显:

import polars as pl
import glob

# 定义文件匹配规则
tsv_pattern = "*.biobank.tsv.gz"
df_list = []

for fn in glob.glob(tsv_pattern):
    # 仅读取需要的两列,单文件去重后保持顺序
    single_df = pl.read_csv(
        fn,
        separator='\t',
        schema_overrides={"#chrom": pl.String},
        n_threads=8,
        columns=["#chrom", "pos"],
        new_columns=["chr", "pos"]
    ).unique(maintain_order=True)
    df_list.append(single_df)

# 合并所有有序小表后按有序规则去重,仅需相邻对比,1600万行几乎秒出结果
global_unique_df = pl.concat(df_list).unique(maintain_order=True)
# 可根据需要导出结果:global_unique_df.write_csv("final_unique_chr_pos.csv")

方案2:无中间文件的DuckDB优化实现

你提到的Polars+DuckDB方案可以进一步简化,省略中间导出Parquet的磁盘IO步骤,DuckDB支持直接读取批量压缩TSV文件,一步完成全局去重:

import duckdb

# 直接批量扫描所有gz文件,向量化执行一步去重
duck_conn = duckdb.connect()
global_unique_df = duck_conn.execute("""
    SELECT DISTINCT "#chrom" AS chr, pos 
    FROM read_csv(
        '*.biobank.tsv.gz', 
        sep = '\t', 
        columns = {'#chrom': 'VARCHAR', 'pos': 'BIGINT'},
        auto_detect = FALSE
    )
""").pl()

方案选型参考

  • 若后续需要继续用Polars处理结果数据,优先选方案1,全程保持Polars生态无额外转换开销
  • 若追求极致的查询效率、不需要额外处理中间过程,优先选方案2,DuckDB的多文件批量扫描优化比手动遍历文件效率更高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 12:24:02