Uma tabela de expressão diferencial (DEG) é um ponto de partida útil—mas raramente é o fim da história. A maioria das pessoas enfrenta a mesma pergunta seguinte: o que significam essas alterações a nível de genes em termos de vias e funções biológicas? É aí que entra a análise de enriquecimento funcional.
Este guia de estilo de recurso mostra um fluxo de trabalho completo e repetível em R: QC → normalização → expressão diferencial → enriquecimento (ORA e GSEA) → visualização, utilizando o clusterProfiler (um pacote R do Bioconductor) para enriquecimento e gráficos amigáveis ao enriquecimento. Está escrito de forma a que possa copiar a estrutura para o seu próprio caderno de análise ou adaptá-la para um pequeno script. Também encontrará um esqueleto compacto de script R perto do final.
Ao longo do caminho, iremos focar-nos nos detalhes práticos que tendem a ser mais importantes em projetos reais: formatos de entrada, IDs de genes, o universo genético de fundo, como escolher entre ORA e GSEA, e como fazer os três gráficos que as pessoas realmente utilizam (vulcão + barra + ponto).
Se ainda está a decidir como definir limiares, interpretar log2FC e FDR, ou estruturar a sua tabela de DEG para análise posterior, pode achar útil esta visão geral da expressão diferencial: Análise de Expressão Génica Diferencial.
Visão geral do fluxo de trabalho do pipeline de enriquecimento DEG baseado em clusterProfiler.
Quando terminar este fluxo de trabalho, deverá ter um pequeno conjunto de resultados que são fáceis de reutilizar e partilhar:
Se estiver a escrever um post de blog no estilo de métodos ou um SOP interno, estas saídas mapeiam-se bem para uma estrutura de pastas simples:
Opção A: Começar a partir das contagens (recomendado)
Você tem:
Esta é a rota mais limpa porque você controla toda a cadeia.
Opção B: Começar a partir de uma tabela DEG (mais rápida)
Já tem resultados do DESeq2/edgeR/limma:
Isto é bom para enriquecimento desde que a tabela DEG esteja bem formada e que você possa reconstruir uma classificação para GSEA se desejar.
Nos fluxos de enriquecimento, o momento mais comum de "por que isto está vazio?" é uma incompatibilidade de ID.
IDs típicos que você verá:
O clusterProfiler pode trabalhar com múltiplos tipos, mas muitos fluxos de trabalho GO/KEGG são mais simples se converter para ENTREZID para enriquecimento. A abordagem prática é:
Essa tabela de mapeamento torna-se a sua "cola" quando precisa interpretar os resultados ou construir listas de genes para análises de acompanhamento.
Uma pilha comum e estável parece assim:
Nota: A disponibilidade e o comportamento do KEGG podem variar consoante o organismo e a forma como os IDs são tratados. Se estiver a trabalhar com uma espécie menos comum, o GO pode ser mais direto do que o KEGG, a menos que tenha um forte suporte de anotação.
O QC não precisa ser complicado, mas deve ser intencional. O objetivo é simples: certifique-se de que as suas amostras se comportem como o seu desenho de estudo espera.
Três verificações cobrem muito terreno:
A PCA é rápida, visual e geralmente informativa.
Visualização de QC de amostras baseada em PCA.
Diferenças pequenas são normais. Diferenças grandes podem ser um sinal de problemas técnicos.
Uma nota prática sobre outliers:
Se remover uma amostra, escreva. porquê Em uma frase e mantenha um registo. Mesmo para trabalho interno, o seu eu futuro ficará grato.
A normalização é uma daquelas palavras que significa coisas diferentes em contextos diferentes.
Para a expressão diferencial, a maioria dos métodos estabelecidos espera contagens brutas e realiza a normalização como parte do modelo:
Um desvio frequente é usar TPM/FPKM para DE. O TPM é útil para certos tipos de comparações, mas para DE baseado em contagens geralmente cria mais perguntas do que responde. Se o seu objetivo é um teste diferencial fiável, mantenha-se na via baseada em contagens.
Algum filtragem é útil:
A filtragem melhora a potência e reduz o ruído, especialmente em estudos pequenos.
A sua tabela DEG é o ponto de articulação entre estatísticas a nível de genes e enriquecimento. Uma tabela DEG "boa" para enriquecimento a montante inclui:
Um ponto de partida comum é:
Mas muitas análises beneficiam de ser um pouco mais flexíveis:
Se souber que o seu sinal é subtil (ou que o seu tamanho de amostra é modesto), considere optar mais pela GSEA baseada em classificações em vez de tentar "forçar" uma grande lista de DEG.
Para a ORA, é frequentemente informativo realizar a enriquecimento separadamente para:
Isso mantém a direcionalidade clara. Caso contrário, pode acabar com um conjunto de genes misto onde um termo está "enriquecido", mas os genes nele se movem em ambas as direções.
Este é o núcleo do guia. O clusterProfiler suporta várias abordagens de enriquecimento, mas duas são especialmente comuns para RNA-seq interpretação:
Entradas de que precisa
Sobre o universo (conjunto de genes de fundo)
Se não definir um universo, a sua enriquecimento é frequentemente comparado a um amplo fundo padrão da base de dados de anotações. Em muitos casos, um universo mais prático e defensável é:
Isto alinha o fundo de enriquecimento com o que o seu experimento poderia detetar realisticamente.
Enriquecimento GO (ponto de partida recomendado)
Enriquecimento KEGG (opcional)
O KEGG pode ser muito útil, mas também é onde problemas de ID e organismo surgem com mais frequência. Se o KEGG retornar resultados vazios:
A GSEA altera a questão. Em vez de selecionar um "subconjunto de genes significativos", classifica todos os genes por uma estatística e pergunta se os genes de uma via tendem a aparecer perto do topo ou do fundo.
O que precisa para GSEA
Classificação de escolhas que são fáceis de explicar
Se optar pela abordagem do valor p log assinado, proteja-se contra zeros e NAs (por exemplo, limite os valores p a um mínimo como 1e-300).
Este fluxo de trabalho foca intencionalmente em três gráficos porque eles cobrem a maioria das necessidades sem transformar a sua redação numa coleção de figuras.
Um gráfico de volcano mostra:
Bons hábitos:
Gráfico de vulcão resumindo os resultados da expressão diferencial.
Utilize gráficos de barras para mostrar uma lista curta dos principais termos enriquecidos. Mantenha-a concisa:
Os dotplots são um ótimo resumo "de um painel":
Se publicar gráficos de pontos, mantenha a legenda legível e evite mostrar muitos termos.
Gráfico de pontos resumindo termos funcionais enriquecidos com codificação de tamanho e cor.
Esta secção destina-se a ser uma lista de verificação rápida "antes de exportar resultados".
Dica: exporte uma tabela de mapeamento e mantenha-a com os seus resultados. Isso evita confusões mais tarde.
Se os resultados da ORA parecerem estranhos (demasiado amplos, demasiado vazios, demasiado genéricos), reverta ao universo.
Um padrão prático:
Se não está satisfeito com os resultados do ORA, experimente o GSEA antes de reescrever os seus limiares cinco vezes.
O GO é hierárquico e redundante por natureza. Se os seus principais resultados parecerem repetições:
Razões comuns:
Um gráfico que é tecnicamente correto pode ainda ser difícil de ler.
Abaixo está um esqueleto de script compacto que você pode adaptar. Presume-se que:
É intencionalmente minimalista para que possa ser incluído num download de recursos de blog e permitir que os leitores modifiquem algumas linhas.
suppressPackageStartupMessages({
biblioteca(DESeq2)
biblioteca(clusterProfiler)
biblioteca(enrichplot)
biblioteca(AnnotationDbi)
biblioteca(org.Hs.eg.db) # substitua pelo seu organismo
biblioteca(ggplot2)
biblioteca(dplyr)
})
# ---- Entradas (editar) ----
counts_file <- "counts.csv" # genes x amostras, contagens brutas
meta_file <- "meta.csv" # amostra, condição (e lote opcional)
id_type_in <- "SÍMBOLO" # SÍMBOLO ou ENSEMBL
cond_a <- "tratado"
cond_b <- "controlo"
dir.create("tabelas", showWarnings = FALSE)
dir.create("plots", showWarnings = FALSE)
# ---- Carregar ----
counts <- read.csv(counts_file, row.names = 1, check.names = FALSE)
meta <- read.csv(meta_file, stringsAsFactors = FALSE)
counts <- counts[, meta$amostra]
# ---- PT ----
dds <- DESeqDataSetFromMatrix(
countData = round(as.matrix(contagens)),
colData = data.frame(meta, row.names = meta$sample),
design = ~ condição
)
# Filtragem simples
dds <- dds[rowSums(counts(dds) >= 10) >= 2, ]
dds <- DESeq(dds)
res <- resultados(dds, contraste = c("condição", cond_a, cond_b))
res <- as.data.frame(res) %>%
mutar(gene = nomes_linhas(.)) %>%
filtrar(!é.na(padj))
escrever.csv(res, "tabelas/DEG_resultados.csv", row.names = FALSE)
# ---- Vulcão ----
vol <- res %>% mutate(sig = padj < 0.05 & abs(log2FoldChange) >= 1)
p_vol <- ggplot(vol, aes(log2FoldChange, -log10(padj))) +
geom_point(aes(alpha = sig), size = 1) +
scale_alpha_manual(values = c(`TRUE` = 0.8, `FALSE` = 0.2), guide = "nenhum") +
theme_bw() +
labs(x = "Mudança de Fold log2", y = "-log10(FDR)", title = "Gráfico de Vulcão")
ggsave("plots/volcano.pdf", p_vol, largura = 6.5, altura = 5)
# ---- Mapeamento de ID ----
mapeado <- bitr(res$gene,
fromType = id_tipo_em,
toType = "ENTREZID",
OrgDb = org.Hs.eg.db)
res_entrez <- res %>%
inner_join(mapeado, por = c("gene" = tipo_id_em)) %>%
distinct(ENTREZID, .keep_all = TRUE)
escrever.csv(res_entrez, "tabelas/DEG_com_ENTREZID.csv", nomes.linhas = FALSE)
write.csv(mapped, "tabelas/ID_mapping.csv", row.names = FALSE)
# ---- ORA (VAI BP) ----
deg_up <- res_entrez %>% filtrar(padj < 0.05, log2FoldChange >= 1) %>% puxar(ENTREZID)
deg_dn <- res_entrez %>% filtrar(padj < 0.05, log2FoldChange <= -1) %>% puxar(ENTREZID)
universo <- res_entrez$ENTREZID
ego_up <- enrichGO(gene = deg_up, universo = universe,
OrgDb = org.Hs.eg.db, tipoChave = "ENTREZID",
ont = "BP", pAdjustMethod = "BH", qvalueCutoff = 0.05)
ego_dn <- enrichGO(gene = deg_dn, universo = universo,
OrgDb = org.Hs.eg.db, tipoChave = "ENTREZID",
ont = "BP", pAdjustMethod = "BH", qvalueCutoff = 0.05)
escrever.csv(as.data.frame(ego_up), "tabelas/GO_ORA_up.csv", row.names = FALSE)
write.csv(as.data.frame(ego_dn), "tabelas/GO_ORA_para_baixo.csv", row.names = FALSE)
# ---- Gráficos: barra + ponto ----
ggsave("plots/GO_ORA_up_bar.pdf", barplot(ego_up, showCategory = 15), largura = 7, altura = 5)
ggsave("plots/GO_ORA_up_dot.pdf", dotplot(ego_up, showCategory = 15), largura = 7, altura = 5)
# ---- Opcional: GSEA ----
rank_vec <- res_entrez$estat
se (todos(is.na(rank_vec))) {
p <- pmax(res_entrez$pvalue, 1e-300)
rank_vec <- sign(res_entrez$log2FoldChange) * -log10(p)
}
names(rank_vec) <- res_entrez$ENTREZID
rank_vec <- sort(rank_vec, decreasing = TRUE)
gse_bp <- gseGO(geneList = rank_vec,
OrgDb = org.Hs.eg.db, tipoChave = "ENTREZID",
ont = "BP", pAdjustMethod = "BH", verbose = FALSE)
write.csv(as.data.frame(gse_bp), "tabelas/GO_GSEA_BP.csv", row.names = FALSE)
ggsave("plots/GO_GSEA_dot.pdf", dotplot(gse_bp, showCategory = 15), largura = 7, altura = 5)
Como transformar isto num recurso descarregável.
Preciso de executar o DESeq2 para usar o clusterProfiler?
Não. Você pode usar o clusterProfiler com resultados de qualquer método de DE, desde que tenha uma lista de genes para ORA ou um vetor de genes ordenados para GSEA.
Devo usar ORA ou GSEA para enriquecimento de vias?
Use ORA quando quiser enriquecimento em um conjunto de DEG selecionado. Use GSEA quando preferir testar o enriquecimento em uma lista classificada sem depender de um limite rigoroso.
Por que é que a enriquecimento não retorna resultados?
Na maioria das vezes, é uma incompatibilidade de ID/organismo (especialmente para KEGG) ou a lista de entrada é muito pequena. Verificar a conversão de ID e mudar para GSEA são soluções comuns.
O que devo usar como conjunto de genes de fundo (universo) para ORA?
Um padrão prático é o conjunto de genes testados na sua análise DE (depois da filtragem), e não o genoma inteiro.
Quantos termos devo plotar?
Normalmente, 10 a 20 termos são suficientes para uma figura clara; mais do que isso tende a tornar-se repetitivo e difícil de ler.
Referências: