polars-bio 是做什麼的?
概述
polars-bio 是一個高效能的 Python 函式庫,專用於基因體區間操作和生物資訊檔案 I/O,建立在 Polars、Apache Arrow 和 Apache DataFusion 之上。它提供熟悉的 DataFrame 為中心的 API,用於區間算術(重疊、最近、合併、覆蓋、補集、減集)以及讀寫常見的生物資訊格式(BED、VCF、BAM、CRAM、GFF/GTF、FASTA、FASTQ)。
關鍵價值主張:
- 比 bioframe 快 6-38 倍(基於真實基因體基準測試)
- 支援串流/超記憶體處理大型基因體,透過 DataFusion
- 雲端原生檔案 I/O(S3、GCS、Azure),具備謂詞下推功能
- 兩種 API 風格:函數式(
pb.overlap(df1, df2))和方法鏈式(df1.lazy().pb.overlap(df2)) - SQL 介面用於基因體資料,透過 DataFusion SQL 引擎
何時使用此技能
在下列情況使用此技能:
- 執行基因體區間操作(重疊、最近、合併、覆蓋、補集、減集)
- 讀寫生物資訊檔案格式(BED、VCF、BAM、CRAM、GFF/GTF、FASTA、FASTQ)
- 處理記憶體無法容納的大型基因體資料集(串流模式)
- 對基因體資料檔案執行 SQL 查詢
- 從 bioframe 遷移到更快的替代方案
- 從 BAM/CRAM 檔案計算讀取深度/堆疊
- 處理包含基因體區間的 Polars DataFrame
快速開始
安裝
需要 Python 3.11–3.14(請參閱 PyPI)。
uv pip install "polars-bio==0.31.0"
為相容 pandas(pandas ≥3.0):
uv pip install "polars-bio[pandas]==0.31.0"
基本重疊範例
import polars as pl
import polars_bio as pb
# 建立兩個區間 DataFrame
df1 = pl.DataFrame({
"chrom": ["chr1", "chr1", "chr1"],
"start": [1, 5, 22],
"end": [6, 9, 30],
})
df2 = pl.DataFrame({
"chrom": ["chr1", "chr1"],
"start": [3, 25],
"end": [8, 28],
})
# 函數式 API(預設回傳 LazyFrame)
result = pb.overlap(df1, df2)
result_df = result.collect()
# 直接取得 DataFrame
result_df = pb.overlap(df1, df2, output_type="polars.DataFrame")
# 方法鏈式 API(透過 LazyFrame 上的 .pb 存取器)
result = df1.lazy().pb.overlap(df2)
result_df = result.collect()
讀取 BED 檔案
import polars_bio as pb
# Eager 讀取(載入整個檔案)
df = pb.read_bed("regions.bed")
# Lazy 掃描(串流,適用於大型檔案)
lf = pb.scan_bed("regions.bed")
result = lf.collect()
核心功能
1. 基因體區間操作
polars-bio 提供 8 種核心區間操作,用於基因體範圍算術。所有操作都接受包含 chrom、start、end 欄位(可設定)的 Polars DataFrame。所有操作預設回傳 LazyFrame(使用 output_type="polars.DataFrame" 可取得 eager 結果)。
操作:
overlap/count_overlaps- 尋找或計算兩個區間集之間的重疊區間(自 0.30.0 版本起,overlap_output="left"僅回傳 df1 的命中結果)nearest- 尋找最近的區間(可設定k、overlap、distance參數)merge- 合併同一集合內重疊/相鄰的區間cluster- 為重疊區間指派叢集 IDcoverage- 計算每個區間的覆蓋計數(雙輸入操作)complement- 尋找基因體內區間之間的間隙subtract- 移除與另一個集合重疊的區間部分
範例:
import polars_bio as pb
# 尋找重疊區間(回傳 LazyFrame)
result = pb.overlap(df1, df2, suffixes=("_1", "_2"))
# 計算每個區間的重疊次數
counts = pb.count_overlaps(df1, df2)
# 合併重疊區間
merged = pb.merge(df1)
# 尋找最近區間
nearest = pb.nearest(df1, df2)
# 將任何 LazyFrame 結果收集為 DataFrame
result_df = result.collect()
參考: 請參閱 references/interval_operations.md 以取得所有操作的詳細文件,包括參數、輸出結構和效能考量。
2. 生物資訊檔案 I/O
使用 read_*、scan_*、write_* 和 sink_* 函數讀寫常見的生物資訊格式。支援雲端儲存(S3、GCS、Azure)和壓縮(GZIP、BGZF)。
支援的格式:
- BED - 基因體區間(
read_bed、scan_bed,透過通用方式進行write_*) - VCF - 遺傳變異(
read_vcf、scan_vcf、write_vcf、sink_vcf) - VCF Zarr - 分析就緒的 Zarr 儲存(
read_vcf_zarr、scan_vcf_zarr;本地目錄路徑) - BAM - 比對讀取(
read_bam、scan_bam、write_bam、sink_bam) - CRAM - 壓縮比對(
read_cram、scan_cram、write_cram、sink_cram) - GFF - 基因註釋(
read_gff、scan_gff) - GTF - 基因註釋(
read_gtf、scan_gtf) - FASTA - 參考序列(
read_fasta、scan_fasta、write_fasta、sink_fasta) - FASTQ - 定序讀取(
read_fastq、scan_fastq、write_fastq、sink_fastq) - SAM - 文字比對(
read_sam、scan_sam、write_sam、sink_sam) - Hi-C 配對 - 染色質接觸(
read_pairs、scan_pairs)
範例:
import polars_bio as pb
# 讀取 VCF 檔案
variants = pb.read_vcf("samples.vcf.gz")
# Lazy 掃描 BAM 檔案(串流)
alignments = pb.scan_bam("aligned.bam")
# 讀取 GFF 註釋
genes = pb.read_gff("annotations.gff3")
# 雲端儲存(個別參數,非字典)
df = pb.read_bed("s3://bucket/regions.bed",
allow_anonymous=True)
參考: 請參閱 references/file_io.md 以取得各格式的欄位結構、參數、雲端儲存選項和壓縮支援。
3. SQL 資料處理
將生物資訊檔案註冊為資料表,並使用 DataFusion SQL 進行查詢。結合 SQL 的強大功能與 polars-bio 的基因體感知讀取器。
import polars as pl
import polars_bio as pb
# 將檔案註冊為 SQL 資料表(路徑在前,name= 關鍵字)
pb.register_vcf("samples.vcf.gz", name="variants")
pb.register_bed("target_regions.bed", name="regions")
# 使用 SQL 查詢(回傳 LazyFrame)
result = pb.sql("SELECT chrom, start, end, ref, alt FROM variants WHERE qual > 30")
result_df = result.collect()
# 將 Polars DataFrame 註冊為 SQL 資料表
pb.from_polars("my_intervals", df)
result = pb.sql("SELECT * FROM my_intervals WHERE chrom = 'chr1'").collect()
參考: 請參閱 references/sql_processing.md 以取得註冊函數、SQL 語法和範例。
4. 堆疊操作
從 BAM/CRAM 檔案計算每個鹼基的讀取深度,並進行 CIGAR 感知深度計算。
import polars_bio as pb
# 計算整個 BAM 檔案的深度
depth_lf = pb.depth("aligned.bam")
depth_df = depth_lf.collect()
# 搭配品質過濾
depth_lf = pb.depth("aligned.bam", min_mapping_quality=20)
參考: 請參閱 references/pileup_operations.md 以取得參數和整合模式。
關鍵概念
座標系統
polars-bio 預設使用 1-based 座標(基因體慣例)。可以全域更改:
import polars_bio as pb
# 切換至 0-based 半開區間座標(預設為 1-based / False)
pb.set_option("datafusion.bio.coordinate_system_zero_based", True)
# 切回 1-based(預設)
pb.set_option("datafusion.bio.coordinate_system_zero_based", False)
I/O 函數也接受 use_zero_based 參數,用來在結果 DataFrame 上設定座標 metadata:
# 讀取 BED 並明確指定 0-based metadata
df = pb.read_bed("regions.bed", use_zero_based=True)
重要: BED 檔案在檔案格式中始終是 0-based 半開區間。polars-bio 在讀取 BED 檔案時會自動處理轉換。座標 metadata 由 I/O 函數附加到 DataFrame,並透過操作傳播。
兩種 API 風格
函數式 API - 獨立函數,明確輸入:
result = pb.overlap(df1, df2, suffixes=("_1", "_2"))
merged = pb.merge(df)
方法鏈式 API - 透過 LazyFrames 上的 .pb 存取器(非 DataFrame):
result = df1.lazy().pb.overlap(df2)
merged = df.lazy().pb.merge()
重要: 區間操作的 .pb 存取器僅適用於 LazyFrame。在 DataFrame 上,.pb 僅提供寫入操作(write_bam、write_vcf 等)。
方法鏈式可實現流暢的管線:
# 鏈接區間操作(注意:overlap 輸出有後綴的欄位,
# 因此需先重新命名,再進行需要 chrom/start/end 的 merge)
result = (
df1.lazy()
.pb.overlap(df2)
.filter(pl.col("start_2") > 1000)
.select(
pl.col("chrom_1").alias("chrom"),
pl.col("start_1").alias("start"),
pl.col("end_1").alias("end"),
)
.pb.merge()
.collect()
)
探針-建構架構
對於雙輸入操作(overlap、nearest、count_overlaps、coverage),polars-bio 使用探針-建構連接策略:
- 第一個 DataFrame 是 探針(迭代對象)
- 第二個 DataFrame 是 建構(建立索引以供查詢)
為獲得最佳效能,請將較大的 DataFrame 作為第一個參數(探針),較小的作為第二個(建構)。
欄位慣例
預設情況下,polars-bio 期望欄位名稱為 chrom、start、end。可以透過列表指定自訂欄位名稱:
result = pb.overlap(
df1, df2,
cols1=["chromosome", "begin", "finish"],
cols2=["chr", "pos_start", "pos_end"],
)
回傳類型和收集結果
所有區間操作和 pb.sql() 預設回傳 LazyFrame。使用 .collect() 來具體化結果,或傳入 output_type="polars.DataFrame" 以進行 eager 評估:
# Lazy(預設)- 需要時再收集
result_lf = pb.overlap(df1, df2)
result_df = result_lf.collect()
# Eager - 直接取得 DataFrame
result_df = pb.overlap(df1, df2, output_type="polars.DataFrame")
串流與超記憶體處理
對於大於可用 RAM 的資料集,請使用 scan_* 函數和串流執行:
# Lazy 掃描檔案
lf = pb.scan_bed("large_intervals.bed")
# 使用 Polars 串流處理(需要 polars ≥1.37,已隨 polars-bio 捆綁)
result = lf.collect(engine="streaming")
DataFusion 串流預設啟用於區間操作,以批次處理資料,無需將整個資料集載入記憶體。
常見陷阱
-
DataFrame 與 LazyFrame 上的
.pb存取器: 區間操作(overlap、merge 等)僅在LazyFrame.pb上可用。DataFrame.pb僅有寫入方法。在鏈接區間操作前,請使用.lazy()進行轉換。 -
LazyFrame 回傳: 所有區間操作和
pb.sql()預設回傳LazyFrame。別忘了.collect()或使用output_type="polars.DataFrame"。 -
欄位名稱不匹配: polars-bio 預期
chrom、start、end。如果你的欄位有不同的名稱,請使用cols1/cols2參數(作為列表)。 -
座標系統 metadata: 區間操作從 I/O 函數或 DataFrame 的
config_meta讀取座標 metadata。對於手動建立的 DataFrame,請設定df.config_meta.set(coordinate_system_zero_based=True)(0-based)或False(1-based)。如果缺少 metadata,polars-bio 會回退到全域的datafusion.bio.coordinate_system_zero_based設定(並發出警告)。設定pb.set_option("datafusion.bio.coordinate_system_check", True)會改為引發MissingCoordinateSystemError。輸入之間系統不匹配會引發CoordinateSystemMismatchError。 -
探針-建構順序很重要: 對於 overlap、nearest 和 coverage,第一個 DataFrame 會針對第二個進行探測。交換參數會改變哪些區間出現在左側或右側輸出欄位中,並可能影響效能。
-
INT32 位置限制: 基因體位置儲存為 32 位元整數,將座標限制在大約 21 億。這對於所有已知基因體都是足夠的,但在自訂座標空間中可能會有問題。
-
BAM 索引需求:
read_bam和scan_bam需要 BAM 旁邊有一個.bai索引檔案。如果缺少,請使用samtools index建立一個。 -
預設停用並行執行: DataFusion 並行處理預設為 1 個分區。對大型資料集啟用:
pb.set_option("datafusion.execution.target_partitions", 8) -
CRAM 有獨立的函數: 對於 CRAM 檔案,請使用
read_cram/scan_cram/register_cram(而非read_bam)。CRAM 函數需要reference_path參數。
最佳實踐
-
對大型檔案使用
scan_*: 對大於可用 RAM 的檔案,優先使用scan_bed、scan_vcf等,而非read_*。Scan 函數支援串流和謂詞下推。 -
為大型資料集設定並行處理:
import os pb.set_option("datafusion.execution.target_partitions", os.cpu_count()) -
使用 BGZF 壓縮: BGZF 壓縮檔案(
.bed.gz、.vcf.gz)支援並行區塊解壓縮,遠比純 GZIP 快速。 -
盡早選取欄位: 當只需要特定欄位時,請盡早選取它們以減少記憶體使用:
df = pb.read_vcf("large.vcf.gz").select("chrom", "start", "end", "ref", "alt") -
直接使用雲端路徑: 直接將 S3/GCS/Azure URI 傳遞給 read/scan/register 函數,無需先下載檔案。驗證存取使用您的雲端 SDK 憑證(
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY、GOOGLE_APPLICATION_CREDENTIALS、Azure 預設值),僅在存取這些雲端路徑時使用:df = pb.read_bed("s3://my-bucket/regions.bed", allow_anonymous=True) -
單一操作偏好函數式 API,管線偏好方法鏈式: 對於一次性操作使用
pb.overlap(),在建置多步驟管線時使用.lazy().pb.overlap()。
資源
references/
每個主要功能的詳細文件:
-
interval_operations.md - 所有 8 種區間操作,包含參數、範例、輸出結構和效能提示。基因體範圍算術的核心參考。
-
file_io.md - 支援格式表格、各格式欄位結構、
…
[因翻譯而截斷]