Parte 2·2.7·25 min de leitura

Na Prática: Fundamentos do Biopython

Biopython é o toolkit Python padrão para análise de sequências biológicas — parsing de arquivos GenBank, cálculo de estatísticas de sequências, execução de alinhamentos e trabalho com estruturas.

biopythonpythonpráticasequências

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

bash
pip install biopython

O namespace principal é Bio. Os submódulos são organizados por função:

python
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.

python
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

python
# 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.

python
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:

python
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:

FormatoStringNotas
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

python
# 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:

python
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

python
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

python
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

python
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

python
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

python
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
Limites de taxa do BLAST

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

python
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.

python
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

python
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

python
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óduloUso
Bio.SeqObjeto de sequência central com operações biológicas
Bio.SeqIOLeitura/escrita de todos os formatos de sequência
Bio.SeqRecordSequências com metadados associados
Bio.EntrezAcesso programático ao banco de dados do NCBI
Bio.AlignAlinhamento par a par e de múltiplas sequências
Bio.BlastConsultas BLAST e parsing de resultados
Bio.PDBParsing 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.