Biopython é o mais próximo que a biologia tem de uma biblioteca padrão para análise de sequências. Ele encapsula bancos de dados do NCBI, analisa dezenas de formatos de arquivo, implementa algoritmos clássicos e fornece estruturas de dados criadas especificamente para sequências biológicas. Se você está escrevendo código Python que trabalha com sequências, quase certamente está usando Biopython.
Este capítulo cobre os fluxos de trabalho principais: trabalhar com sequências, analisar formatos de arquivo comuns, computar propriedades de sequências, alinhar sequências e uma breve introdução ao tratamento de estruturas.
Instalação e Configuração
pip install biopython
O namespace principal é Bio. Os submódulos são organizados por função:
from Bio import SeqIO # Parsing de arquivos e E/S de sequências
from Bio.Seq import Seq # O objeto Seq central
from Bio import Entrez # Acesso ao banco de dados do NCBI
from Bio import Align # Alinhamento par a par e múltiplo
from Bio import pairwise2 # Alinhamento par a par legado
from Bio.PDB import PDBParser # Parsing de estruturas
O Objeto Seq
A abstração fundamental é Bio.Seq.Seq — um objeto semelhante a string que sabe que representa uma sequência biológica e suporta operações biológicas.
from Bio.Seq import Seq
# Criar uma sequência
dna = Seq("ATGCGATCGATCGATCG")
# Operações semelhantes a string funcionam como esperado
print(len(dna)) # 18
print(dna[0:6]) # ATGCGA
print(dna.count("ATG")) # 1
# Operações específicas de biologia
print(dna.complement()) # TACGCTAGCTAGCTAGC
print(dna.reverse_complement()) # CGATCGATCGATCGCAT
# Transcrição: DNA → RNA (T → U)
rna = dna.transcribe()
print(rna) # AUGCGAUCGAUCGAUCG
# Tradução: RNA → proteína
protein = rna.translate()
print(protein) # MRSS* (onde * é o códon de parada)
# DNA → proteína direto
protein = dna.translate()
print(protein) # MRSS*
print(protein[:-1]) # Remover códon de parada: MRSS
Alfabetos e Tipos de Sequências
# Por padrão, Seq é sem tipo — funciona para DNA, RNA ou proteína
# Para sequências de RNA, use U em vez de T
rna = Seq("AUGCGAUCG")
# MutableSeq permite modificação in-place
from Bio.Seq import MutableSeq
mseq = MutableSeq("ATGCGATCG")
mseq[0] = "G" # substituição pontual
print(mseq) # GTGCGATCG
SeqRecord: Sequências com Metadados
O objeto SeqRecord combina uma Seq com seu identificador, nome, descrição e features.
from Bio.SeqRecord import SeqRecord
from Bio.Seq import Seq
record = SeqRecord(
Seq("ATGCGATCGATCG"),
id="NM_007294",
name="BRCA1",
description="Homo sapiens BRCA1 mRNA",
annotations={"molecule_type": "mRNA"}
)
print(record.id) # NM_007294
print(record.seq) # ATGCGATCGATCG
print(record.description) # Homo sapiens BRCA1 mRNA
Parsing de Arquivos com SeqIO
Bio.SeqIO lê e escreve todos os formatos comuns de sequências biológicas. A interface é consistente independentemente do formato:
from Bio import SeqIO
# Analisar um arquivo FASTA
records = list(SeqIO.parse("sequences.fasta", "fasta"))
for record in records:
print(f"{record.id}: {len(record.seq)} pb")
# Analisar um arquivo GenBank
for record in SeqIO.parse("brca1.gb", "genbank"):
print(record.id)
print(record.description)
print(f"Features: {len(record.features)}")
# Ler um único registro
record = SeqIO.read("single.fasta", "fasta") # levanta ValueError se >1 registro
Formatos Suportados
Formatos comuns e suas strings de formato:
| Formato | String | Notas |
|---|---|---|
| FASTA | "fasta" | Mais comum; sem anotações |
| GenBank | "genbank" ou "gb" | Anotações completas, features |
| FASTQ | "fastq" | Sequências + pontuações de qualidade |
| EMBL | "embl" | Equivalente europeu do GenBank |
| Stockholm | "stockholm" | Alinhamentos de múltiplas sequências |
| Clustal | "clustal" | Alinhamentos de múltiplas sequências |
Escrevendo Sequências
# Escrever em FASTA
SeqIO.write(records, "output.fasta", "fasta")
# Converter entre formatos
with open("output.gb", "w") as f:
SeqIO.write(records, f, "genbank")
# Converter FASTQ → FASTA
records = SeqIO.parse("reads.fastq", "fastq")
SeqIO.write(records, "reads.fasta", "fasta")
Trabalhando com Features do GenBank
Registros GenBank contêm anotações ricas de features. Features são objetos SeqFeature com tipo, localização e qualificadores:
record = SeqIO.read("brca1.gb", "genbank")
for feature in record.features:
print(f"Tipo: {feature.type}")
print(f"Localização: {feature.location}")
print(f"Fita: {feature.location.strand}") # 1 (forward) ou -1 (reverse)
# Filtrar por features CDS
cds_features = [f for f in record.features if f.type == "CDS"]
for cds in cds_features:
gene = cds.qualifiers.get("gene", ["unknown"])[0]
protein_id = cds.qualifiers.get("protein_id", ["?"])[0]
# Extrair a sequência CDS (trata junções e fita)
cds_seq = cds.extract(record.seq)
protein = cds_seq.translate(to_stop=True)
print(f"{gene} ({protein_id}): {len(protein)} aa")
Localizações de Features
from Bio.SeqFeature import SimpleLocation
feature = record.features[0]
loc = feature.location
print(loc.start) # início baseado em 0 (ExactPosition)
print(loc.end) # fim baseado em 0 (ExactPosition)
print(loc.strand) # 1 ou -1
# Verificar se é composto (com splicing)
from Bio.SeqFeature import CompoundLocation
if isinstance(loc, CompoundLocation):
for part in loc.parts:
print(f" Éxon: {part.start}–{part.end}")
Análise de Sequências
Conteúdo GC e Composição
from Bio.SeqUtils import gc_fraction
seq = Seq("ATGCGATCGATCGATCG")
gc = gc_fraction(seq)
print(f"Conteúdo GC: {gc:.1%}") # 47.1%
# Composição manual
from collections import Counter
counts = Counter(str(seq))
print(counts)
Encontrando ORFs
def find_orfs(seq: Seq, min_length: int = 100) -> list:
orfs = []
for strand, nuc in [(+1, seq), (-1, seq.reverse_complement())]:
for frame in range(3):
i = frame
while i < len(nuc) - 2:
codon = nuc[i:i+3]
if codon == "ATG":
for j in range(i, len(nuc) - 2, 3):
if nuc[j:j+3] in ("TAA", "TAG", "TGA"):
orf_len = j + 3 - i
if orf_len >= min_length:
orfs.append({
"start": i, "end": j + 3,
"strand": strand, "frame": frame,
"length": orf_len, "seq": nuc[i:j+3]
})
break
i += 3
return sorted(orfs, key=lambda x: -x["length"])
Alinhamento de Sequências
Alinhamento Par a Par
from Bio import Align
aligner = Align.PairwiseAligner()
aligner.mode = "global" # Needleman-Wunsch
# aligner.mode = "local" # Smith-Waterman
aligner.match_score = 2
aligner.mismatch_score = -1
aligner.open_gap_score = -2
aligner.extend_gap_score = -0.5
seq1 = Seq("ATGCGATCG")
seq2 = Seq("ATGCAATCG")
alignments = aligner.align(seq1, seq2)
best = alignments[0]
print(f"Pontuação: {best.score}")
print(best)
Consultas BLAST via NCBI
from Bio.Blast import NCBIWWW, NCBIXML
result_handle = NCBIWWW.qblast(
"blastn", # programa: blastn, blastp, blastx, tblastn, tblastx
"nt", # banco de dados: nt, nr, refseq_rna, etc.
"ATGCGATCGATCG", # sequência query
hitlist_size=10
)
blast_records = NCBIXML.parse(result_handle)
blast_record = next(blast_records)
for alignment in blast_record.alignments:
for hsp in alignment.hsps:
print(f"Match: {alignment.title[:60]}")
print(f"Pontuação: {hsp.score}, E-valor: {hsp.expect:.2e}")
print(f"Identidade: {hsp.identities}/{hsp.align_length}")
break
O serviço web BLAST do NCBI limita o uso intensivo. Para fluxos de trabalho de produção com muitas sequências, instale o BLAST+ localmente e execute blastn / blastp como ferramentas de linha de comando. Biopython pode analisar a saída XML com NCBIXML.
Trabalhando com Alinhamentos de Múltiplas Sequências
from Bio import AlignIO
from collections import Counter
# Analisar um arquivo de alinhamento Clustal
alignment = AlignIO.read("sequences.aln", "clustal")
print(f"Comprimento do alinhamento: {alignment.get_alignment_length()}")
print(f"Número de sequências: {len(alignment)}")
# Obter uma coluna do alinhamento
col_10 = alignment[:, 10] # coluna 10, todas as sequências
print(f"Coluna 10: {col_10}")
# Calcular conservação por posição
def column_identity(alignment, position: int) -> float:
col = alignment[:, position]
most_common = Counter(col).most_common(1)[0][1]
return most_common / len(col)
Fundamentos de Estrutura com Bio.PDB
Para estruturas 3D de proteínas, Biopython fornece uma hierarquia: Estrutura → Modelo → Cadeia → Resíduo → Átomo.
from Bio.PDB import PDBParser
import urllib.request
# Baixar e analisar
urllib.request.urlretrieve("https://files.rcsb.org/download/1JM7.pdb", "1JM7.pdb")
parser = PDBParser(QUIET=True)
structure = parser.get_structure("1JM7", "1JM7.pdb")
# Navegar pela hierarquia
model = structure[0] # primeiro MODEL
chain = model["A"] # cadeia A
residue = chain[100] # resíduo 100
atom = residue["CA"] # carbono alfa
print(f"Coordenadas CA: {atom.get_vector()}")
# Todos os resíduos na cadeia A
residues = [r for r in chain.get_residues() if r.get_id()[0] == " "]
print(f"Resíduos padrão na cadeia A: {len(residues)}")
Calculando Distâncias
def get_ca_distance(res1, res2) -> float:
ca1 = res1["CA"].get_vector()
ca2 = res2["CA"].get_vector()
return (ca1 - ca2).norm()
res10 = chain[10]
res50 = chain[50]
dist = get_ca_distance(res10, res50)
print(f"Distância Cα: {dist:.2f} Å")
Pipeline Prático: Fluxo de Trabalho de Análise de Sequências
from Bio import Entrez, SeqIO
from Bio.SeqUtils import gc_fraction
from Bio.Seq import Seq
import time
Entrez.email = "seu@email.com"
def analyze_gene(gene_name: str, organism: str = "Homo sapiens") -> dict:
handle = Entrez.esearch(
db="nucleotide",
term=f"{gene_name}[Gene Name] AND {organism}[Organism] AND RefSeq[Filter] AND mRNA[Filter]",
retmax=1
)
result = Entrez.read(handle)
handle.close()
if not result["IdList"]:
return {"error": "Gene não encontrado"}
time.sleep(0.4)
handle = Entrez.efetch(db="nucleotide", id=result["IdList"][0], rettype="gb", retmode="text")
record = SeqIO.read(handle, "genbank")
handle.close()
cds_features = [f for f in record.features if f.type == "CDS"]
analysis = {
"accession": record.id,
"total_length_bp": len(record.seq),
"gc_content": gc_fraction(record.seq),
"cds_count": len(cds_features),
}
if cds_features:
cds_seq = cds_features[0].extract(record.seq)
protein = cds_seq.translate(to_stop=True)
analysis["protein_length_aa"] = len(protein)
analysis["protein_gc"] = gc_fraction(cds_seq)
return analysis
result = analyze_gene("BRCA1")
for key, value in result.items():
print(f"{key}: {value}")
Resumo
Os módulos principais do Biopython:
| Módulo | Uso |
|---|---|
Bio.Seq | Objeto de sequência central com operações biológicas |
Bio.SeqIO | Leitura/escrita de todos os formatos de sequência |
Bio.SeqRecord | Sequências com metadados associados |
Bio.Entrez | Acesso programático ao banco de dados do NCBI |
Bio.Align | Alinhamento par a par e de múltiplas sequências |
Bio.Blast | Consultas BLAST e parsing de resultados |
Bio.PDB | Parsing e análise de estruturas 3D |
Para quase qualquer tarefa de análise de sequências biológicas em Python, comece com Biopython. Se descobrir que ele não cobre seu caso de uso, procure bibliotecas dedicadas: pyvcf/cyvcf2 para arquivos VCF, pysam para arquivos SAM/BAM, scanpy para análise de célula única, BioPandas para fluxos de trabalho de estrutura como DataFrame.