O que polars-bio faz?
Visão Geral
polars-bio é uma biblioteca Python de alto desempenho para operações em intervalos genômicos e E/S de arquivos bioinformáticos, construída sobre Polars, Apache Arrow e Apache DataFusion. Ela fornece uma API familiar centrada em DataFrames para aritmética de intervalos (sobreposição, mais próximo, mescla, cobertura, complemento, subtração) e leitura/escrita de formatos bioinformáticos comuns (BED, VCF, BAM, CRAM, GFF/GTF, FASTA, FASTQ).
Principais propostas de valor:
- 6 a 38 vezes mais rápido que o bioframe em benchmarks genômicos reais
- Suporte a streaming/fora do núcleo para grandes genomas via DataFusion
- E/S nativa em nuvem (S3, GCS, Azure) com pushdown de predicados
- Dois estilos de API: funcional (
pb.overlap(df1, df2)) e encadeamento de métodos (df1.lazy().pb.overlap(df2)) - Interface SQL para dados genômicos via mecanismo SQL DataFusion
Quando Usar Esta Skill
Use esta skill quando:
- Realizar operações em intervalos genômicos (sobreposição, mais próximo, mescla, cobertura, complemento, subtração)
- Ler/escrever formatos de arquivos bioinformáticos (BED, VCF, BAM, CRAM, GFF/GTF, FASTA, FASTQ)
- Processar grandes conjuntos de dados genômicos que não cabem na memória (modo streaming)
- Executar consultas SQL em arquivos de dados genômicos
- Migrar do bioframe para uma alternativa mais rápida
- Calcular profundidade de leitura/pileup de arquivos BAM/CRAM
- Trabalhar com DataFrames Polars contendo intervalos genômicos
Início Rápido
Instalação
Requer Python 3.11–3.14 (veja PyPI).
uv pip install "polars-bio==0.31.0"
Para compatibilidade com pandas (pandas ≥3.0):
uv pip install "polars-bio[pandas]==0.31.0"
Exemplo Básico de Sobreposição
import polars as pl
import polars_bio as pb
# Criar dois DataFrames de intervalo
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 funcional (retorna LazyFrame por padrão)
resultado = pb.overlap(df1, df2)
df_resultado = resultado.collect()
# Obter um DataFrame diretamente
df_resultado = pb.overlap(df1, df2, output_type="polars.DataFrame")
# API de encadeamento de métodos (via acessador .pb em LazyFrame)
resultado = df1.lazy().pb.overlap(df2)
df_resultado = resultado.collect()
Lendo um Arquivo BED
import polars_bio as pb
# Leitura eager (carrega todo o arquivo)
df = pb.read_bed("regions.bed")
# Leitura lazy (streaming, para arquivos grandes)
lf = pb.scan_bed("regions.bed")
resultado = lf.collect()
Capacidades Principais
1. Operações de Intervalo Genômico
polars-bio fornece 8 operações principais de intervalo para aritmética de intervalos genômicos. Todas as operações aceitam DataFrames Polars com colunas chrom, start, end (configuráveis). Todas as operações retornam um LazyFrame por padrão (use output_type="polars.DataFrame" para resultados eager).
Operações:
overlap/count_overlaps- Encontrar ou contar intervalos sobrepostos entre dois conjuntos (overlap_output="left"retorna apenas hits de df1 desde 0.30.0)nearest- Encontrar intervalos mais próximos (com parâmetros configuráveisk,overlap,distance)merge- Mesclar intervalos sobrepostos/adjacentes dentro de um conjuntocluster- Atribuir IDs de cluster a intervalos sobrepostoscoverage- Calcular contagens de cobertura por intervalo (operação de duas entradas)complement- Encontrar lacunas entre intervalos dentro de um genomasubtract- Remover partes de intervalos que se sobrepõem a outro conjunto
Exemplo:
import polars_bio as pb
# Encontrar intervalos sobrepostos (retorna LazyFrame)
resultado = pb.overlap(df1, df2, suffixes=("_1", "_2"))
# Contar sobreposições por intervalo
contagens = pb.count_overlaps(df1, df2)
# Mesclar intervalos sobrepostos
mesclado = pb.merge(df1)
# Encontrar intervalos mais próximos
mais_proximo = pb.nearest(df1, df2)
# Coletar qualquer resultado LazyFrame para DataFrame
df_resultado = resultado.collect()
Referência: Consulte references/interval_operations.md para documentação detalhada sobre todas as operações, parâmetros, schemas de saída e considerações de desempenho.
2. E/S de Arquivos Bioinformáticos
Leia e escreva formatos bioinformáticos comuns com funções read_*, scan_*, write_* e sink_*. Suporta armazenamento em nuvem (S3, GCS, Azure) e compressão (GZIP, BGZF).
Formatos suportados:
- BED - Intervalos genômicos (
read_bed,scan_bed,write_*via genérico) - VCF - Variantes genéticas (
read_vcf,scan_vcf,write_vcf,sink_vcf) - VCF Zarr - Armazenamentos Zarr prontos para análise (
read_vcf_zarr,scan_vcf_zarr; caminhos de diretório local) - BAM - Leituras alinhadas (
read_bam,scan_bam,write_bam,sink_bam) - CRAM - Alinhamentos comprimidos (
read_cram,scan_cram,write_cram,sink_cram) - GFF - Anotações gênicas (
read_gff,scan_gff) - GTF - Anotações gênicas (
read_gtf,scan_gtf) - FASTA - Sequências de referência (
read_fasta,scan_fasta,write_fasta,sink_fasta) - FASTQ - Leituras de sequenciamento (
read_fastq,scan_fastq,write_fastq,sink_fastq) - SAM - Alinhamentos de texto (
read_sam,scan_sam,write_sam,sink_sam) - Pares Hi-C - Contatos de cromatina (
read_pairs,scan_pairs)
Exemplo:
import polars_bio as pb
# Ler arquivo VCF
variantes = pb.read_vcf("samples.vcf.gz")
# Leitura lazy de arquivo BAM (streaming)
alinhamentos = pb.scan_bam("aligned.bam")
# Ler anotações GFF
genes = pb.read_gff("annotations.gff3")
# Armazenamento em nuvem (parâmetros individuais, não um dicionário)
df = pb.read_bed("s3://bucket/regions.bed",
allow_anonymous=True)
Referência: Consulte references/file_io.md para schemas de colunas por formato, parâmetros, opções de armazenamento em nuvem e suporte a compressão.
3. Processamento de Dados SQL
Registre arquivos bioinformáticos como tabelas e consulte-os usando SQL DataFusion. Combina o poder do SQL com os leitores cientes de genoma do polars-bio.
import polars as pl
import polars_bio as pb
# Registrar arquivos como tabelas SQL (caminho primeiro, name= como palavra-chave)
pb.register_vcf("samples.vcf.gz", name="variants")
pb.register_bed("target_regions.bed", name="regions")
# Consultar com SQL (retorna LazyFrame)
resultado = pb.sql("SELECT chrom, start, end, ref, alt FROM variants WHERE qual > 30")
df_resultado = resultado.collect()
# Registrar um DataFrame Polars como tabela SQL
pb.from_polars("my_intervals", df)
resultado = pb.sql("SELECT * FROM my_intervals WHERE chrom = 'chr1'").collect()
Referência: Consulte references/sql_processing.md para funções de registro, sintaxe SQL e exemplos.
4. Operações de Pileup
Calcule a profundidade de leitura por base de arquivos BAM/CRAM com cálculo de profundidade ciente de CIGAR.
import polars_bio as pb
# Calcular profundidade em um arquivo BAM
profundidade_lf = pb.depth("aligned.bam")
profundidade_df = profundidade_lf.collect()
# Com filtro de qualidade
profundidade_lf = pb.depth("aligned.bam", min_mapping_quality=20)
Referência: Consulte references/pileup_operations.md para parâmetros e padrões de integração.
Conceitos Chave
Sistemas de Coordenadas
polars-bio usa coordenadas baseadas em 1 por padrão (convenção genômica). Isso pode ser alterado globalmente:
import polars_bio as pb
# Mudar para coordenadas semiabertas baseadas em 0 (o padrão é baseado em 1 / False)
pb.set_option("datafusion.bio.coordinate_system_zero_based", True)
# Voltar para baseado em 1 (padrão)
pb.set_option("datafusion.bio.coordinate_system_zero_based", False)
As funções de E/S também aceitam use_zero_based para definir metadados de coordenadas no DataFrame resultante:
# Ler BED com metadados explícitos baseados em 0
df = pb.read_bed("regions.bed", use_zero_based=True)
Importante: Arquivos BED são sempre semiabertos baseados em 0 no formato do arquivo. polars-bio lida automaticamente com a conversão ao ler arquivos BED. Metadados de coordenadas são anexados aos DataFrames pelas funções de E/S e propagados através das operações.
Dois Estilos de API
API funcional - funções independentes, entradas explícitas:
resultado = pb.overlap(df1, df2, suffixes=("_1", "_2"))
mesclado = pb.merge(df)
API de encadeamento de métodos - via acessador .pb em LazyFrames (não DataFrames):
resultado = df1.lazy().pb.overlap(df2)
mesclado = df.lazy().pb.merge()
Importante: O acessador .pb para operações de intervalo está disponível apenas em LazyFrame. Em DataFrame, .pb fornece apenas operações de escrita (write_bam, write_vcf, etc.).
O encadeamento de métodos permite pipelines fluidos:
# Encadear operações de intervalo (nota: overlap produz colunas com sufixo,
# então renomeie antes de merge que espera chrom/start/end)
resultado = (
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()
)
Arquitetura Sonda-Construção
Para operações de duas entradas (overlap, nearest, count_overlaps, coverage), polars-bio usa uma estratégia de junção sonda-construção:
- O primeiro DataFrame é a sonda (iterado)
- O segundo DataFrame é a construção (indexado para consulta)
Para melhor desempenho, passe o DataFrame maior como primeiro argumento (sonda) e o menor como segundo (construção).
Convenções de Colunas
Por padrão, polars-bio espera colunas chamadas chrom, start, end. Nomes de colunas personalizados podem ser especificados via listas:
resultado = pb.overlap(
df1, df2,
cols1=["chromosome", "begin", "finish"],
cols2=["chr", "pos_start", "pos_end"],
)
Tipos de Retorno e Coleta de Resultados
Todas as operações de intervalo e pb.sql() retornam um LazyFrame por padrão. Use .collect() para materializar resultados, ou passe output_type="polars.DataFrame" para avaliação eager:
# Lazy (padrão) - colete quando necessário
resultado_lf = pb.overlap(df1, df2)
df_resultado = resultado_lf.collect()
# Eager - obtenha DataFrame diretamente
df_resultado = pb.overlap(df1, df2, output_type="polars.DataFrame")
Processamento em Streaming e Fora do Núcleo
Para conjuntos de dados maiores que a RAM disponível, use funções scan_* e execução em streaming:
# Escanear arquivos lazymente
lf = pb.scan_bed("large_intervals.bed")
# Processar com streaming do Polars (requer polars ≥1.37, incluído com polars-bio)
resultado = lf.collect(engine="streaming")
O streaming DataFusion é ativado por padrão para operações de intervalo, processando dados em lotes sem carregar o conjunto de dados completo na memória.
Armadilhas Comuns
-
Acessador
.pbem DataFrame vs LazyFrame: Operações de intervalo (overlap, merge, etc.) estão apenas emLazyFrame.pb.DataFrame.pbpossui apenas métodos de escrita. Use.lazy()para converter antes de encadear operações de intervalo. -
Retornos LazyFrame: Todas as operações de intervalo e
pb.sql()retornamLazyFramepor padrão. Não esqueça.collect()ou useoutput_type="polars.DataFrame". -
Incompatibilidade de nomes de colunas: polars-bio espera
chrom,start,endpor padrão. Use os parâmetroscols1/cols2(como listas) se suas colunas tiverem nomes diferentes. -
Metadados do sistema de coordenadas: Operações de intervalo leem metadados de coordenadas de funções de E/S ou
config_metado DataFrame. Para DataFrames construídos manualmente, definadf.config_meta.set(coordinate_system_zero_based=True)(baseado em 0) ouFalse(baseado em 1). Se os metadados estiverem ausentes, polars-bio usa a configuração globaldatafusion.bio.coordinate_system_zero_based(com um aviso). Definapb.set_option("datafusion.bio.coordinate_system_check", True)para gerarMissingCoordinateSystemErrorem vez disso. Sistemas incompatíveis entre entradas geramCoordinateSystemMismatchError. -
A ordem sonda-construção importa: Para overlap, nearest e coverage, o primeiro DataFrame é sondado contra o segundo. Trocar argumentos altera quais intervalos aparecem nas colunas de saída esquerda vs direita e pode afetar o desempenho.
-
Limite de posição INT32: Posições genômicas são armazenadas como inteiros de 32 bits, limitando as coordenadas a ~2,1 bilhões. Isso é suficiente para todos os genomas conhecidos, mas pode ser um problema com espaços de coordenadas personalizados.
-
Requisitos de índice BAM:
read_bamescan_bamrequerem um arquivo de índice.baijunto com o BAM. Crie um comsamtools indexse estiver faltando. -
Execução paralela desativada por padrão: O paralelismo DataFusion padroniza para 1 partição. Ative para grandes conjuntos de dados:
pb.set_option("datafusion.execution.target_partitions", 8) -
CRAM tem funções separadas: Use
read_cram/scan_cram/register_crampara arquivos CRAM (nãoread_bam). Funções CRAM requerem um parâmetroreference_path.
Melhores Práticas
-
Use
scan_*para arquivos grandes: Prefirascan_bed,scan_vcf, etc. em vez deread_*para arquivos maiores que a RAM disponível. As funções Scan habilitam streaming e pushdown de predicados. -
Configure o paralelismo para grandes conjuntos de dados:
import os pb.set_option("datafusion.execution.target_partitions", os.cpu_count()) -
Use compressão BGZF: Arquivos comprimidos com BGZF (
.bed.gz,.vcf.gz) suportam descompressão paralela em blocos, significativamente mais rápida que GZIP simples. -
Selecione colunas cedo: Quando apenas colunas específicas são necessárias, selecione-as cedo para reduzir o uso de memória:
df = pb.read_vcf("large.vcf.gz").select("chrom", "start", "end", "ref", "alt") -
Use caminhos de nuvem diretamente: Passe URIs S3/GCS/Azure diretamente para funções read/scan/register em vez de baixar arquivos primeiro. O acesso autenticado usa as credenciais do seu SDK de nuvem (
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY,GOOGLE_APPLICATION_CREDENTIALS, padrões do Azure) apenas quando esses caminhos de nuvem são acessados:df = pb.read_bed("s3://my-bucket/regions.bed", allow_anonymous=True) -
Prefira API funcional para operações únicas, encadeamento de métodos para pipelines: Use
pb.overlap()para operações pontuais e.lazy().pb.overlap()ao construir pipelines de múltiplas etapas.
Recursos
references/
Documentação detalhada para cada capacidade principal:
-
interval_operations.md - Todas as 8 operações de intervalo com parâmetros, exemplos, schemas de saída e dicas de desempenho. Referência principal para aritmética de intervalos genômicos.
-
file_io.md - Tabela de formatos suportados, schemas de colunas por formato,
…
[truncado para tradução]