Bioconductor
Paquetes esenciales para análisis ómico en R
Sobre Bioconductor
Bioconductor es el ecosistema de paquetes R orientado al análisis de datos biomédicos. Comparte infraestructura con CRAN pero opera con un release cycle propio (dos releases anuales, en abril y octubre, sincronizados con la versión de R). Esto garantiza coherencia entre paquetes pero obliga a fijar la versión correcta cuando reproduces análisis ajenos.
Instalación canónica:
if (!require("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install("DESeq2") # un paquete
BiocManager::install(version = "3.20") # fijar versión del release
BiocManager::valid() # verificar coherencia de versionesTres principios del ecosistema que conviene tener interiorizados:
- Clases S4 compartidas. La mayoría de paquetes consume y devuelve
SummarizedExperimento derivados (DESeqDataSet,SingleCellExperiment,TreeSummarizedExperiment). Esto permite encadenar herramientas sin pegar datos a mano. - Vignettes como documentación principal.
vignette("DESeq2")abre el manual canónico de cada paquete. En la práctica casi siempre es preferible a?función. - Integración con
GenomicRanges. Las coordenadas genómicas se manejan como objetosGRanges, no comodata.frameconchr / start / end.
Esta página cataloga seis paquetes que estructuran la mayor parte de los flujos ómicos en R. El orden refleja jerarquía conceptual: primero la infraestructura (estructura de datos y secuencias), después los modelos de expresión diferencial, y finalmente la aplicación al dominio del microbioma.
SummarizedExperiment
SummarizedExperiment es la clase S4 que estandariza la representación de un experimento en Bioconductor: una matriz de assay (típicamente features × muestras), metadatos de filas (rowData) y de columnas (colData), todo en un objeto coherente.
Es la base sobre la que se construyen casi todos los workflows modernos. DESeqDataSet, SingleCellExperiment, TreeSummarizedExperiment y MultiAssayExperiment heredan o extienden esta clase. Internalizar su API ahorra horas a lo largo de cualquier proyecto serio de Bioconductor.
Cuándo usarlo
Siempre que tengas una matriz de medidas (counts, intensidades, abundancias) asociada a metadatos de muestra y/o de feature. Si tu output natural es un data.frame largo, casi siempre conviene reestructurar a SummarizedExperiment antes de seguir: es el formato que el resto del ecosistema espera.
Conceptos clave
assay(se)accede a la matriz principal.assays(se)si hay varias capas en paralelo (counts, normalized, logcounts…).colData(se)son los metadatos de las muestras (DataFrameS4, nodata.framebase).rowData(se)son los metadatos de las features (genes, taxones, peaks).- Garantía de alineación: el subsetting (
se[1:100, 1:5]) mantiene la coherencia entre assay y metadatos automáticamente, este es el valor real frente a hacerlo con matrices sueltas. RangedSummarizedExperimentextiende la clase añadiendo coordenadas genómicas enrowRanges.
Patrón mínimo
library(SummarizedExperiment)
counts <- matrix(rpois(200, 10), nrow = 20)
rownames(counts) <- paste0("gene", 1:20)
colnames(counts) <- paste0("sample", 1:10)
col_meta <- DataFrame(
condition = rep(c("ctrl", "treat"), each = 5),
batch = rep(c("A", "B"), 5)
)
se <- SummarizedExperiment(
assays = list(counts = counts),
colData = col_meta
)
# Subset preservando la coherencia
se_treated <- se[, se$condition == "treat"]Trampas habituales
- No es
data.frame.se$conditionfunciona como atajo paracolData(se)$condition, pero elcolDatasubyacente esDataFrame(S4): operaciones dedplyrno actúan directamente sobre él. - Múltiples assays. Si necesitas conviven counts y logcounts, usa
assays(se) <- list(counts = ..., logcounts = ...)en lugar de duplicar objetos. assayNames(se)es lo primero que se inspecciona cuando trabajas con código de terceros. Sin ese hábito, te encontrarás multiplicando ramasif.
Enlaces
Biostrings
Biostrings es la librería que representa eficientemente secuencias biológicas (ADN, ARN, proteína) en R. Define las clases DNAString, RNAString, AAString y sus colecciones (DNAStringSet, RNAStringSet, AAStringSet), con búsqueda de patrones, alineamiento básico y operaciones idiomáticas sobre secuencias.
Es la pieza más baja del stack de secuencias en Bioconductor. ShortRead (FASTQ), Rsamtools (BAM) y GenomicAlignments se apoyan en sus clases.
Cuándo usarlo
Manipulación directa de secuencias en R: leer FASTA, búsqueda de motivos, complemento reverso, traducción, k-mers. Cualquier preprocesamiento que no quieras delegar a herramientas externas como seqkit, bedtools o herramientas de alineamiento.
Cuándo NO usarlo
Análisis de lecturas a gran escala (decenas de millones de reads). Ahí entran herramientas fuera de R (BWA, minimap2, STAR) o paquetes que iteran sobre el FASTQ por bloques (ShortRead). En memoria de R, mantén las colecciones por debajo de unos pocos millones de elementos.
Conceptos clave
DNAStringSetes la colección eficiente.DNAStringindividual rara vez se usa solo.- API básica:
width(seqs),subseq(seqs, ...),reverseComplement(seqs),translate(seqs). - Búsqueda:
matchPattern()para una secuencia diana,vmatchPattern()para vectorizar contra una colección. - Soporta códigos IUPAC de ambigüedad y operaciones case-sensitive opcionales.
letterFrequency()yalphabetFrequency()para composición y conteos de k-meros.
Patrón mínimo
library(Biostrings)
# Leer FASTA
seqs <- readDNAStringSet("genome.fasta")
# Estadísticos básicos
width(seqs)
alphabetFrequency(seqs, baseOnly = TRUE)
# Búsqueda de motivo en toda la colección
hits <- vmatchPattern("GAATTC", seqs) # diana EcoRI
# Complemento reverso y traducción a aminoácidos (frame 1)
rc <- reverseComplement(seqs)
proteins <- translate(seqs, if.fuzzy.codon = "solve")Trampas habituales
as.character()es caro. Si vas a iterar sobre una colección, evita convertir a cadena R. Opera con la API S4.matchPatternvsvmatchPattern. El primero acepta una sola secuencia diana. El segundo, una colección. Confundirlos da errores opacos.- Marcos de lectura.
translate()asume frame 1 por defecto. Para los 6 marcos hay que combinarsubseq()+reverseComplement()manualmente.
Enlaces
DESeq2
DESeq2 es el estándar de facto para análisis de expresión diferencial en datos de RNA-seq bulk. Modela los conteos crudos con una distribución binomial negativa, estima la dispersión por gen con shrinkage hacia una curva tendencial, y aplica MAP shrinkage al log-fold-change para estabilizar las estimaciones en genes de baja expresión.
Desarrollado por Michael Love y Wolfgang Huber. Pareja natural con tximport para importar resultados de Salmon, Kallisto o RSEM a conteos a nivel de gen.
Cuándo usarlo
Bulk RNA-seq con réplicas (mínimo 3 por condición). Diseños factoriales con interacciones. Datasets de hasta ~100 muestras. Más allá, limma-voom es notablemente más rápido y suele ser preferible.
Cuándo NO usarlo
- Single-cell. No está diseñado para zero-inflation extremo. Usa
glmGamPoi,MASTo el patrón de pseudobulk + DESeq2 sobre el agregado. - Datos ya normalizados. DESeq2 exige conteos crudos enteros. Pasarle TPM, RPKM o FPKM rompe los supuestos.
- Una sola réplica por condición. El modelo necesita estimar dispersión. N = 1 no es viable.
Conceptos clave
DESeqDataSethereda deSummarizedExperiment. Eldesign(fórmula) y el assay"counts"son obligatorios.DESeq()ejecuta tres pasos en uno:estimateSizeFactors(),estimateDispersions(),nbinomWaldTest().results()extrae la tabla. El contraste se especifica concontrast = c("variable", "nivel_num", "nivel_denom")o conname = "...".lfcShrink()(apeglm,ashronormal) corrige el LFC para ranking y visualización. Imprescindible para MA-plots, heatmaps y gene set enrichment downstream.- Independent filtering.
results()filtra automáticamente genes de bajo conteo para mejorar el poder estadístico. Ese filtro aparece reportado ensummary(res).
Patrón mínimo
library(DESeq2)
# Suponiendo `counts` (matriz integer genes × samples) y `coldata` (DataFrame)
coldata$condition <- factor(coldata$condition, levels = c("ctrl", "treat"))
dds <- DESeqDataSetFromMatrix(
countData = counts,
colData = coldata,
design = ~ batch + condition # variable de interés al final
)
# Prefiltrado opcional (acelera; no es obligatorio)
keep <- rowSums(counts(dds) >= 10) >= 3
dds <- dds[keep, ]
# Modelo
dds <- DESeq(dds)
# Resultados con shrinkage del LFC
res <- lfcShrink(dds, coef = "condition_treat_vs_ctrl", type = "apeglm")
summary(res)Trampas habituales
- Orden de niveles del factor. El nivel de referencia (típicamente
ctrl) debe ser el primero. Fijarlo explícitamente confactor(..., levels = ...)evita sorpresas en el signo del LFC. - Variable de interés al final del
design. Convención de DESeq2: cuando no se pasacontrastniname,results()devuelve el contraste del último término. Coloca siempre la variable principal al final. - Filtrar antes vs después. Filtrar genes con counts muy bajos antes de
DESeq()es opcional. El independent filtering dentro deresults()lo hace después, basado enbaseMean. No filtres con criterios sesgados (p. ej. varianza alta), invalidan la corrección de p-values. - Batch effects en
design, no en los datos. Incluirlos como covariable (~ batch + condition) es correcto. AplicarremoveBatchEffect()y pasar esos counts al modelo no lo es.
Enlaces
Relacionados en esta página
SummarizedExperiment, clase base delDESeqDataSet.edgeRylimma, alternativas para el mismo problema.
edgeR
edgeR resuelve el mismo problema que DESeq2, expresión diferencial sobre conteos, pero con una filosofía empírica Bayes ligeramente distinta: moderación de la dispersión por gen mediante estimación trended / tagwise, y test cuasi-likelihood F (QL F-test) en la versión moderna.
Desarrollado por el grupo de Gordon Smyth en WEHI. Suele dar resultados muy similares a DESeq2 en términos prácticos. Las diferencias importan en diseños complejos y en datasets de tamaño medio-alto donde el test QL F rinde mejor que el Wald de DESeq2.
Cuándo usarlo
- Mismo nicho que DESeq2 (bulk RNA-seq con réplicas).
- Diseños factoriales complejos con interacciones y contrastes múltiples, el QL F-test es generalmente más conservador y robusto.
- Cuando ya estás integrado en el ecosistema limma para visualización o pasos posteriores.
Conceptos clave
DGEListes la estructura propia (no hereda deSummarizedExperiment, aunque hay conversión bidireccional).- Pipeline moderno recomendado:
calcNormFactors()(TMM) →estimateDisp()→glmQLFit()→glmQLFTest(). - La función legacy
exactTest()solo aplica a comparaciones de dos grupos. Evítala en diseños reales con más de una covariable. - TMM (Trimmed Mean of M-values) ajusta por composición. Es diferente a la mediana de ratios de DESeq2 pero filosóficamente equivalente, ambos intentan corregir el efecto de unos pocos genes muy expresados sobre el tamaño efectivo de la librería.
Patrón mínimo
library(edgeR)
y <- DGEList(counts = counts, group = coldata$condition)
# Filtrado recomendado por el propio paquete
keep <- filterByExpr(y, group = coldata$condition)
y <- y[keep, , keep.lib.sizes = FALSE]
# Normalización por composición
y <- calcNormFactors(y, method = "TMM")
# Modelo
design <- model.matrix(~ batch + condition, data = coldata)
y <- estimateDisp(y, design)
fit <- glmQLFit(y, design)
qlf <- glmQLFTest(fit, coef = "conditiontreat")
topTags(qlf)Trampas habituales
exactTest()no escala a diseños complejos. Si tu modelo tiene más de una covariable, usaglmQLFit+glmQLFTest.filterByExpr()ya considera eldesign. Diseñado para filtrar de forma estadísticamente válida. No filtres a mano sin entender qué hace.- TMM no produce conteos normalizados que se pasen a otra herramienta, produce factores de normalización que el modelo aplica internamente. Si necesitas exportar conteos normalizados para visualización, usa
cpm(y, normalized.lib.sizes = TRUE).
Enlaces
Relacionados en esta página
DESeq2, alternativa con MAP shrinkage del LFC.limma, del mismo grupo (WEHI), preferible para n grande.
limma
limma es la librería original de modelos lineales aplicados a expresión génica, primero microarrays, después adaptada a RNA-seq vía la transformación voom (variance modeling at the observational level). El combo limma + voom es la opción natural cuando tienes muchas muestras o diseños complejos: rinde más rápido que DESeq2 / edgeR y aguanta contrastes sofisticados (makeContrasts, eBayes) con elegancia.
Es además la pieza con la que se hacen los contrastes “raros”: correlaciones within-subject (duplicateCorrelation), ANOVA factorial con interacciones, ajustes por confounders, modelos con efectos aleatorios moderados.
Cuándo usarlo
- n alto (>20 muestras) o muchas condiciones. La transformación
voomconvierte counts en log-CPM con pesos de precisión y permite aplicar la maquinaria lineal clásica. - Microarrays (caso histórico, aún común en datasets antiguos o plataformas Affymetrix HTA).
- Diseños donde necesitas
makeContrastscon múltiples comparaciones nombradas y simétricas.
Conceptos clave
voom(counts, design)produce unEListcon log-CPM y matriz de pesos. A partir de ahí,lmFit+contrasts.fit+eBayeses el pipeline estándar.eBayes()modera el error estándar de los t-stats mediante empirical Bayes, comparte información entre genes para estabilizar los tests.topTable()extrae la tabla de resultados (equivalente aresults()en DESeq2 otopTags()en edgeR).- Para correlaciones dentro de sujeto (datos pareados), usa
duplicateCorrelation()antes delmFit.
Patrón mínimo
library(limma)
library(edgeR) # para DGEList y filterByExpr
y <- DGEList(counts = counts)
keep <- filterByExpr(y, group = coldata$condition)
y <- y[keep, , keep.lib.sizes = FALSE]
y <- calcNormFactors(y)
design <- model.matrix(~ 0 + condition + batch, data = coldata)
colnames(design) <- gsub("condition", "", colnames(design))
v <- voom(y, design, plot = FALSE)
fit <- lmFit(v, design)
contrasts <- makeContrasts(treat_vs_ctrl = treat - ctrl, levels = design)
fit2 <- contrasts.fit(fit, contrasts)
fit2 <- eBayes(fit2)
topTable(fit2, coef = "treat_vs_ctrl", number = 20)Trampas habituales
- No mezcles
voomcon datos ya normalizados. La entrada debe ser counts crudos integrados enDGEList+calcNormFactors. Pasarle TPM o log-counts rompe el modelo de pesos. ~ condition(con intercept) vs~ 0 + condition(sin). El segundo facilitamakeContrastscon nombres claros (treat - ctrl). El primero contrasta automáticamente contra el nivel de referencia. Para diseños factoriales, el patrón sin intercept es más legible.eBayes(trend = TRUE)activa el modo limma-trend, alternativa avoomcuando la varianza no depende fuertemente del nivel de expresión. Útil con counts ya transformados (p. ej. CPM logarítmicos) cuando no quieres pesos.
Enlaces
Relacionados en esta página
phyloseq
phyloseq es el framework dominante para análisis integrado de microbioma en R: combina tabla de abundancias (OTU/ASV), taxonomía, metadatos de muestra y opcionalmente filogenia y secuencias representativas, en un objeto único (phyloseq-class). Cierra el ciclo desde la salida de DADA2 (o QIIME2) hasta los análisis estadísticos y la visualización.
Desarrollado por Paul J. McMurdie y Susan Holmes. Maduro y muy extendido en publicaciones, aunque su ritmo de desarrollo se ha enlentecido frente a alternativas modernas basadas en el stack de Bioconductor (ver más abajo).
Cuándo usarlo
- Datos de amplicon (16S, 18S, ITS) o shotgun metagenómica representados como tabla de abundancia + taxonomía + metadatos.
- Diversidad alfa (
estimate_richness) y beta (distance+ordinate). - Visualización rápida con
plot_bar,plot_ordination,plot_heatmap.
Cuándo NO usarlo (alternativas modernas)
- Para un proyecto nuevo, considera
mia/miaVizoMicrobiotaProcess, construidos sobreTreeSummarizedExperiment, son compatibles con el resto de Bioconductor moderno y mejor mantenidos. - Para downstream avanzado (modelos jerárquicos, longitudinal),
microbiome,ANCOMBCyALDEx2ofrecen métodos más recientes que los disponibles dentro de phyloseq.
Conceptos clave
- El objeto integra hasta cinco slots:
otu_table,tax_table,sample_data,phy_tree,refseq. No todos son obligatorios. taxa_are_rows(physeq)indica la orientación de la matriz. Compruébalo siempre antes de operar sobre filas/columnas, es la fuente número uno de errores opacos.prune_samples()/prune_taxa()hacen subsetting preservando la coherencia entre todos los slots.- Rarefacción:
rarefy_even_depth()está disponible, pero el propio McMurdie publicó en 2014 una crítica argumentando que es estadísticamente subóptima. Para tests formales, prefiere modelos sobre counts crudos (DESeq2, edgeR aplicados al microbioma, ANCOMBC, ALDEx2).
Patrón mínimo
library(phyloseq)
# Asumiendo otu_mat (matriz numérica), tax_mat (matriz de taxonomía con
# rangos como columnas) y sample_df (data.frame con metadatos).
OTU <- otu_table(otu_mat, taxa_are_rows = TRUE)
TAX <- tax_table(tax_mat)
SAM <- sample_data(sample_df)
ps <- phyloseq(OTU, TAX, SAM)
# Diversidad alfa
alpha <- estimate_richness(ps, measures = c("Shannon", "Simpson", "Observed"))
# Ordenación beta (Bray-Curtis + PCoA)
ord <- ordinate(ps, method = "PCoA", distance = "bray")
plot_ordination(ps, ord, color = "condition") + ggplot2::theme_bw()Trampas habituales
taxa_are_rows. Confundir la orientación de la matriz lleva a errores opacos. Convención típica de DADA2: ASVs en filas. Convención típica de QIIME (BIOM): muestras en filas. Compruébalo siempre tras un import.- Importar desde QIIME2.
qiime2R(fuera de Bioconductor) facilita el puente. El import directo del.qzaes frágil y dependiente de la versión. - Rarefacción por ritual. Muy común en literatura pero criticable. Considera tests sobre counts crudos con normalización dentro del modelo (DESeq2, edgeR) o pruebas adaptadas a composición (ALDEx2, ANCOMBC).
Enlaces
Relacionados en esta página
SummarizedExperiment, base de las alternativas modernas tipoTreeSummarizedExperiment.DESeq2, útil también para tests de abundancia diferencial en datos de microbioma con counts crudos.