Este tutorial presenta un análisis de expresión diferencial
utilizando datos de RNA-seq en el telencéfalo de ratón, utilizando el
paquete DESeq2 en R. Los pasos incluyen normalización,
análisis de expresión diferencial y visualización de resultados,
fundamentales para interpretar cambios de expresión bajo condiciones
experimentales específicas. Para más detalles, consulta el artículo en
Frontiers
in Genetics.
Identificar genes diferencialmente expresados entre las condiciones experimentales “M9.5” y “M10.5”, aplicando métodos de normalización y visualización para detectar genes relevantes sin intrones diferencialmente expresados. Los términos M9.5 y M10.5 se refieren a estadios embrionarios en el desarrollo de ratones, expresados en días post coitum (dpc) o días después de la fertilización. Estos números indican la cantidad de días desde la concepción, y cada punto decimal marca fracciones del día.
En la investigación en biología del desarrollo, los estadios embrionarios específicos son críticos para comprender el proceso de diferenciación celular y formación de tejidos. Cada día (e incluso cada fracción de día) en el desarrollo del ratón corresponde a cambios rápidos y específicos en la formación de órganos y sistemas.
Después de la secuenciación, se obtienen archivos FASTQ que requieren procesamiento en BASH para eliminar lecturas de baja calidad y adaptadores. Este paso sí incluye código y se puede realizar con herramientas como FastQC para evaluación de calidad y Trimmomatic para recorte y filtrado.
fastqc sample_R1.fastq sample_R2.fastq -o output_directory/.
Recorte de adaptadores y bases de baja calidad con Trimmomatic
trimmomatic PE -phred33
sample_R1.fastq sample_R2.fastq
sample_R1_trimmed.fastq sample_R1_unpaired.fastq
sample_R2_trimmed.fastq sample_R2_unpaired.fastq
ILLUMINACLIP:TruSeq3-PE.fa:2:30:10 LEADING:3 TRAILING:3
SLIDINGWINDOW:4:15 MINLEN:36.
Para alinear las lecturas al genoma del ratón (mm10), se puede utilizar Tophat o HISAT2. Aquí mostramos el uso de Tophat.
tophat2 -o output_directory/ -G mm10_annotation.gtf mm10_index sample_R1_trimmed.fastq sample_R2_trimmed.fastq. Esto generará un archivo BAM con las lecturas alineadas.
Para contar las lecturas alineadas en cada gen, se uso HTSeq-count junto con el archivo GTF de Ensembl correspondiente al genoma de ratón (mm10).
htseq-count -f bam -r pos -s no -i gene_id sample_aligned.bam mm10_annotation.gtf > read_counts.txt. Esto generará un archivo BAM con las lecturas alineadas.
Preparación del Ambiente
Primero, instalaremos y cargaremos los paquetes necesarios. Nos aseguraremos de que los paquetes estén instalados antes de cargarlos, para facilitar su uso en otros entornos.
# Instalar y cargar paquetes necesarios
if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager")
if (!requireNamespace("dplyr", quietly = TRUE)) BiocManager::install("dplyr")
if (!requireNamespace("DESeq2", quietly = TRUE)) install.packages("DESeq2")
if (!requireNamespace("pheatmap", quietly = TRUE)) install.packages("pheatmap")
if (!requireNamespace("ggplot2", quietly = TRUE)) install.packages("ggplot2")
#BiocManager::install("DESeq2")
library(DESeq2)
## Loading required package: S4Vectors
## Loading required package: stats4
## Loading required package: BiocGenerics
##
## Attaching package: 'BiocGenerics'
## The following objects are masked from 'package:stats':
##
## IQR, mad, sd, var, xtabs
## The following objects are masked from 'package:base':
##
## anyDuplicated, aperm, append, as.data.frame, basename, cbind,
## colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find,
## get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply,
## match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
## Position, rank, rbind, Reduce, rownames, sapply, setdiff, table,
## tapply, union, unique, unsplit, which.max, which.min
##
## Attaching package: 'S4Vectors'
## The following object is masked from 'package:utils':
##
## findMatches
## The following objects are masked from 'package:base':
##
## expand.grid, I, unname
## Loading required package: IRanges
## Loading required package: GenomicRanges
## Loading required package: GenomeInfoDb
## Loading required package: SummarizedExperiment
## Loading required package: MatrixGenerics
## Loading required package: matrixStats
##
## Attaching package: 'MatrixGenerics'
## The following objects are masked from 'package:matrixStats':
##
## colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse,
## colCounts, colCummaxs, colCummins, colCumprods, colCumsums,
## colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs,
## colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats,
## colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
## colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads,
## colWeightedMeans, colWeightedMedians, colWeightedSds,
## colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet,
## rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods,
## rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
## rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins,
## rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks,
## rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars,
## rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
## rowWeightedSds, rowWeightedVars
## Loading required package: Biobase
## Welcome to Bioconductor
##
## Vignettes contain introductory material; view with
## 'browseVignettes()'. To cite Bioconductor, see
## 'citation("Biobase")', and for packages 'citation("pkgname")'.
##
## Attaching package: 'Biobase'
## The following object is masked from 'package:MatrixGenerics':
##
## rowMedians
## The following objects are masked from 'package:matrixStats':
##
## anyMissing, rowMedians
library(dplyr)
##
## Attaching package: 'dplyr'
## The following object is masked from 'package:Biobase':
##
## combine
## The following object is masked from 'package:matrixStats':
##
## count
## The following objects are masked from 'package:GenomicRanges':
##
## intersect, setdiff, union
## The following object is masked from 'package:GenomeInfoDb':
##
## intersect
## The following objects are masked from 'package:IRanges':
##
## collapse, desc, intersect, setdiff, slice, union
## The following objects are masked from 'package:S4Vectors':
##
## first, intersect, rename, setdiff, setequal, union
## The following objects are masked from 'package:BiocGenerics':
##
## combine, intersect, setdiff, union
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2)
library(pheatmap)
Exploración de los Datos de Conteo
Cargamos los datos de conteo de genes desde un archivo de texto que contiene los conteos de cada gen para cada muestra. Para cargar los datos, usaremos el archivo mouse_read_counts.txt. asegurate de que esté en el mismo directorio que este archivo RMarkdown o de lo contrario especifica la ruta completa de localización.
setwd("/Users/katiaavinapadilla/Desktop")
file_path <- "mouse_read_counts.txt"
count_data <- read.table(file_path, header = TRUE, row.names = 1)
head(count_data)
## M9.5a M9.5b M9.5c M9.5d M10.5a M10.5b M10.5c M10.5d
## ENSMUSG00000024112 285 451 169 148 905 783 571 546
## ENSMUSG00000040447 25 20 16 8 175 122 112 74
## ENSMUSG00000096847 454 504 296 255 926 838 576 550
## ENSMUSG00000039860 6 20 5 9 169 133 66 69
## ENSMUSG00000030310 48 54 24 29 379 201 178 169
## ENSMUSG00000034227 124 109 29 35 520 449 288 247
Descripción de los Datos
Cada celda en el conjunto de datos contiene el número de lecturas asignadas a un gen específico en una muestra específica. Estos valores reflejan la expresión relativa de cada gen en cada muestra, pero deben normalizarse para asegurar comparabilidad.
Una matriz de conteos es una representación de datos de RNA-seq que contiene los conteos brutos de lecturas asignadas a cada gen (o transcripto) en cada muestra. Aquí tienes una descripción detallada:
Filas: Cada fila representa un gen o transcripto específico.
Columnas: Cada columna representa una muestra individual.
Celdas: El valor de cada celda es el conteo bruto de lecturas alineadas a ese gen en esa muestra. Estos conteos son enteros y reflejan la abundancia relativa de cada gen en cada muestra.
Información que Proporciona la Matriz de Conteos
Abundancia de Genes: El conteo bruto refleja la abundancia de transcritos de cada gen en una muestra. Los genes con mayor número de conteos son más abundantemente expresados en esa muestra.
Comparabilidad entre Muestras: Aunque los conteos brutos muestran la abundancia, no son directamente comparables entre muestras sin normalización, debido a las diferencias en la profundidad de secuenciación y otros factores técnicos.
Variabilidad entre Genes y Condiciones: Al comparar los conteos entre genes o entre condiciones (como tratamiento y control), podemos inferir patrones de expresión y explorar cómo se regula la expresión génica en diferentes contextos biológicos.
Importancia en el Análisis de Expresión Diferencia
La matriz de conteos es elpunto de partida para el análisis de expresión diferencial. Herramientas de Generación de Matrices de Conteos: HTSeq, FeatureCounts
Conteos Brutos vs. Normalizados: Los conteos brutos reflejan los datos iniciales y se utilizan para la normalización. Los conteos normalizados permiten comparaciones precisas entre muestras.
Creación del Objeto de Condiciones conocido como Metadatos
Definimos las condiciones experimentales, “M9.5” y “M10.5”. Asumimos que cada condición tiene cuatro réplicas, y especificamos estas condiciones en un marco de datos (colData). para usarlas en el análisis de expresión diferencial. La creación del objeto de condiciones o metadatos en un análisis de expresión diferencial es un paso importante, ya que define las categorías o grupos experimentales que queremos comparar. En este caso, estamos trabajando con un conjunto de datos de expresión de genes en el telencéfalo de ratón en dos momentos de desarrollo: “M9.5” y “M10.5”.
¿Por Qué Definir las Condiciones? Al analizar la expresión diferencial con DESeq2, es fundamental indicar al programa qué muestras pertenecen a cada grupo (en este caso, “M9.5” y “M10.5”). Esto permite que el análisis estadístico compare estos grupos para identificar genes cuya expresión cambia significativamente entre las dos condiciones.
samples <- colnames(count_data)
condition <- factor(c(rep("M9.5", 4), rep("M10.5", 4)))
col_data <- data.frame(row.names = samples, condition = condition)
col_data
## condition
## M9.5a M9.5
## M9.5b M9.5
## M9.5c M9.5
## M9.5d M9.5
## M10.5a M10.5
## M10.5b M10.5
## M10.5c M10.5
## M10.5d M10.5
Contenido: Las muestras M9.5a, M9.5b, M9.5c y M9.5d están etiquetadas bajo la condición M9.5. Estas son las cuatro réplicas biológicas de la condición experimental M9.5. Las muestras M10.5a, M10.5b, M10.5c y M10.5d están etiquetadas bajo la condición M10.5, representando las cuatro réplicas biológicas de la condición experimental M10.5.
Creación del Objeto DESeqDataSet
Este marco de datos (col_data) se utiliza para definir las condiciones experimentales de cada muestra cuando se crea el objeto “DESeqDataSet en DESeq2.La columna condition le indica a DESeq2 qué muestras deben compararse en el análisis de expresión diferencial, en este caso, comparando las condiciones M9.5 y M10.5.
Este marco de datos de metadatos permite a DESeq2 identificar qué muestras pertenecen a cada condición experimental, permitiendo realizar la comparación entre las condiciones M9.5 y M10.5 en el análisis de expresión diferencial.
# Crear el objeto DESeqDataSet
dds <- DESeqDataSetFromMatrix(countData = count_data, colData = col_data, design = ~ condition)
# Verificar el contenido del objeto DESeqDataSet
dds
## class: DESeqDataSet
## dim: 12902 8
## metadata(1): version
## assays(1): counts
## rownames(12902): ENSMUSG00000024112 ENSMUSG00000040447 ...
## ENSMUSG00000023391 ENSMUSG00000063804
## rowData names(0):
## colnames(8): M9.5a M9.5b ... M10.5c M10.5d
## colData names(1): condition
Este formato es esencial para el análisis, ya que le indica a DESeq2 cómo están organizadas las condiciones experimentales en el conjunto de datos, permitiéndole realizar comparaciones adecuadas entre los grupos.
Filtrado de Genes con Baja Expresión Para mejorar la precisión del análisis, filtramos los genes con conteos bajos en todas las muestras. Esto reduce el ruido en el análisis y aumenta la potencia estadística. El filtrado de genes con baja expresión se realiza para excluir aquellos genes que no muestran un nivel de expresión significativo en las muestras, ya que pueden agregar “ruido” al análisis estadístico y dificultar la identificación de patrones reales.
¿Qué significa >= 10 y >= 2 en el código?
>= 10: Este umbral especifica que solo se mantendrán los genes que tienen un mínimo de 10 lecturas (conteos) en una muestra. Esto ayuda a eliminar genes con muy baja expresión, que probablemente son ruido o artefactos del experimento en lugar de expresiones biológicamente significativas.
>= 2: Este segundo umbral indica que el gene debe cumplir el criterio anterior (>= 10) en al menos 2 muestras. De esta forma, se garantiza que el gen tiene un nivel mínimo de expresión en más de una muestra, lo cual es importante para la robustez del análisis y permite capturar una expresión que pueda estar presente en un grupo de muestras o condición específica.
# Filtrar genes con baja expresión
dds <- dds[rowSums(counts(dds) >= 10) >= 2, ]
Normalización y Análisis de Expresión Diferencial La función “DESeq () en el paquete DESeq2 realiza tanto la normalización como el análisis de expresión diferencial de los datos de RNA-seq. Aplicamos la función DESeq () para normalizar los datos y calcular la expresión diferencial entre las condiciones “M9.5” y “M10.5”. Este paso incluye la estimación de factores de tamaño y dispersión, y el ajuste de un modelo lineal generalizado para cada gen.
Estimación de Factores de Tamaño: DESeq2 ajusta cada muestra en función de su profundidad de secuenciación mediante la mediana geométrica de conteos. Estimación de Dispersión: DESeq2 estima la dispersión para cada gen, lo que permite distinguir entre variabilidad técnica y biológica. Ajuste del Modelo GLM: DESeq2 ajusta un modelo lineal generalizado para cada gen y calcula el cambio de expresión entre condiciones.
# Ejecutar el análisis de expresión diferencial
dds <- DESeq(dds)
## estimating size factors
## estimating dispersions
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## fitting model and testing
res <- results(dds)
# Visualizar los primeros resultados
head(res)
## log2 fold change (MLE): condition M9.5 vs M10.5
## Wald test p-value: condition M9.5 vs M10.5
## DataFrame with 6 rows and 6 columns
## baseMean log2FoldChange lfcSE stat pvalue
## <numeric> <numeric> <numeric> <numeric> <numeric>
## ENSMUSG00000024112 454.3526 -1.339967 0.188711 -7.10061 1.24204e-12
## ENSMUSG00000040447 64.3561 -2.675618 0.294419 -9.08779 1.01076e-19
## ENSMUSG00000096847 524.4864 -0.816289 0.104892 -7.78221 7.12677e-15
## ENSMUSG00000039860 53.8936 -3.290078 0.376133 -8.74712 2.18876e-18
## ENSMUSG00000030310 125.9156 -2.452229 0.246547 -9.94629 2.61773e-23
## ENSMUSG00000034227 207.0286 -2.266683 0.297384 -7.62208 2.49617e-14
## padj
## <numeric>
## ENSMUSG00000024112 4.33693e-11
## ENSMUSG00000040447 6.50256e-18
## ENSMUSG00000096847 3.05043e-13
## ENSMUSG00000039860 1.24912e-16
## ENSMUSG00000030310 2.12116e-21
## ENSMUSG00000034227 1.01521e-12
Filtrado de Resultados Significativos Filtramos los genes con un valor ajustado (padj) menor a 0.05 para identificar aquellos con cambios significativos en la expresión entre condiciones. Explicación
*res$padj < 0.05: Filtra los genes con un valor ajustado (padj) menor a 0.05, lo que indica significancia estadística después de la corrección por FDR.
*rabs(res$log2FoldChange) > 1 : Filtra los genes cuyo log2 Fold Change (cambio en la expresión entre condiciones) es mayor a 1 en valor absoluto. Esto significa que se seleccionan solo aquellos genes que tienen un cambio de expresión relevante en magnitud.
*El uso de abs() permite seleccionar tanto aumentos como disminuciones en la expresión que cumplan con el criterio de cambio significativo.
# Filtrar genes con cambio de expresión significativo y log2 Fold Change mayor a 1
res_filtered <- res[which(res$padj < 0.05 & abs(res$log2FoldChange) > 1), ]
# Visualizar los genes filtrados
head(res_filtered)
## log2 fold change (MLE): condition M9.5 vs M10.5
## Wald test p-value: condition M9.5 vs M10.5
## DataFrame with 6 rows and 6 columns
## baseMean log2FoldChange lfcSE stat pvalue
## <numeric> <numeric> <numeric> <numeric> <numeric>
## ENSMUSG00000024112 454.3526 -1.33997 0.188711 -7.10061 1.24204e-12
## ENSMUSG00000040447 64.3561 -2.67562 0.294419 -9.08779 1.01076e-19
## ENSMUSG00000039860 53.8936 -3.29008 0.376133 -8.74712 2.18876e-18
## ENSMUSG00000030310 125.9156 -2.45223 0.246547 -9.94629 2.61773e-23
## ENSMUSG00000034227 207.0286 -2.26668 0.297384 -7.62208 2.49617e-14
## ENSMUSG00000034796 80.0761 1.40734 0.239606 5.87353 4.26617e-09
## padj
## <numeric>
## ENSMUSG00000024112 4.33693e-11
## ENSMUSG00000040447 6.50256e-18
## ENSMUSG00000039860 1.24912e-16
## ENSMUSG00000030310 2.12116e-21
## ENSMUSG00000034227 1.01521e-12
## ENSMUSG00000034796 9.63519e-08
Visualización de Resultados
Análisis de Componentes Principales (PCA)
El análisis PCA nos permite visualizar cómo las muestras se agrupan en función de su perfil de expresión, proporcionando una visión general de la variabilidad entre condiciones.
# Transformación de Variance Stabilizing Transformation (VST)
vsd <- vst(dds, blind = FALSE)
plotPCA(vsd, intgroup = "condition") + ggtitle("PCA of Mouse Gene Expression Data")
## using ntop=500 top features by variance
Interpretación: La clara separación a lo largo de PC1 indica que los patrones de expresión génica difieren notablemente entre los grupos M9.5 y M10.5. Esta separación podría deberse a diferencias en las etapas de desarrollo, efectos de tratamiento u otros factores biológicos específicos de cada grupo. La agrupación dentro de cada grupo sugiere consistencia en los perfiles de expresión génica entre los réplicas o muestras dentro del mismo grupo.
Volcano Plot
El Volcano Plot muestra los genes con cambios de expresión significativos, permitiendo identificar visualmente aquellos que tienen mayor cambio de expresión entre condiciones.
# Convertir los resultados a DataFrame para el plot
res_df <- as.data.frame(res)
# Filtrar genes significativos y dividir en inducidos y reprimidos
res_df <- res_df %>%
mutate(gene_label = rownames(res_df)) %>% # Crear columna con los nombres de los genes
mutate(color = case_when(
log2FoldChange > 1 & padj < 0.05 ~ "induced", # Genes inducidos
log2FoldChange < -1 & padj < 0.05 ~ "repressed", # Genes reprimidos
TRUE ~ "neutral" # Genes no significativos
))
# Seleccionar los 5 genes más inducidos y los 5 más reprimidos
top_induced <- res_df %>%
filter(color == "induced") %>%
arrange(desc(log2FoldChange)) %>%
head(5)
top_repressed <- res_df %>%
filter(color == "repressed") %>%
arrange(log2FoldChange) %>%
head(5)
# Crear el Volcano Plot
ggplot(res_df, aes(x = log2FoldChange, y = -log10(padj), color = color)) +
geom_point(alpha = 0.4) +
scale_color_manual(values = c("induced" = "red", "repressed" = "blue", "neutral" = "gray")) +
geom_text(data = top_induced, aes(label = gene_label), vjust = -1, color = "red", size = 1) +
geom_text(data = top_repressed, aes(label = gene_label), vjust = 1.5, color = "blue", size = 1) +
labs(title = "Volcano Plot of Differential Expression",
x = "Log2 Fold Change",
y = "-Log10 Adjusted P-Value") +
theme_minimal()
# Crear una tabla con los 10 genes top (5 up, 5 down)
top_genes <- bind_rows(top_induced, top_repressed) %>%
select(gene_label, log2FoldChange, padj) %>%
arrange(desc(log2FoldChange))
# Mostrar la tabla de los 10 genes top en el documento
knitr::kable(top_genes, caption = "Top 10 Differentially Expressed Genes (5 Induced, 5 Repressed)")
| gene_label | log2FoldChange | padj | |
|---|---|---|---|
| ENSMUSG00000000805 | ENSMUSG00000000805 | 5.092952 | 0.0000000 |
| ENSMUSG00000027750 | ENSMUSG00000027750 | 4.624025 | 0.0000000 |
| ENSMUSG00000023886 | ENSMUSG00000023886 | 4.004762 | 0.0000008 |
| ENSMUSG00000027375 | ENSMUSG00000027375 | 3.981459 | 0.0001192 |
| ENSMUSG00000022510 | ENSMUSG00000022510 | 3.881713 | 0.0062039 |
| ENSMUSG00000019146 | ENSMUSG00000019146 | -7.012011 | 0.0000000 |
| ENSMUSG00000042532 | ENSMUSG00000042532 | -7.146135 | 0.0000000 |
| ENSMUSG00000046178 | ENSMUSG00000046178 | -7.297091 | 0.0000000 |
| ENSMUSG00000000214 | ENSMUSG00000000214 | -7.679289 | 0.0000000 |
| ENSMUSG00000051354 | ENSMUSG00000051354 | -9.588639 | 0.0000000 |
Interpretación:Los puntos en el cuadrante superior derecho (rojo) representan genes significativamente inducidos, y los del cuadrante superior izquierdo (azul) representan genes significativamente reprimidos. La mayoría de los genes inducidos o reprimidos tienen valores p ajustados significativos, lo que sugiere que hay diferencias importantes en la expresión génica entre las condiciones comparadas.Estos genes representan los más afectados en términos de expresión entre las condiciones comparadas. Los genes más inducidos pueden estar asociados con funciones específicas que se activan en la condición experimental, mientras que los genes más reprimidos podrían estar inhibidos o regulados negativamente en respuesta a esa condición.
Heatmap de Genes Significativamente Expresados
Un heatmap nos permite visualizar los patrones de expresión de los genes diferencialmente expresados entre las diferentes muestras. Esto es útil para observar agrupaciones de genes con expresiones similares entre condiciones.
# Obtener conteos normalizados
norm_counts <- counts(dds, normalized = TRUE)
sig_genes <- rownames(res_filtered)
# Crear Heatmap
pheatmap(norm_counts[sig_genes, ],
cluster_rows = TRUE,
cluster_cols = TRUE,
scale = "row",
annotation_col = col_data,
show_rownames = FALSE,
main = "Heatmap of Differentially Expressed Genes")
Interpretación General: Este mapa de calor sugiere que existen patrones de expresión diferencial claros entre M9.5 y M10.5. Los genes en rojo en M10.5 están inducidos en esta condición en comparación con M9.5, mientras que los genes en azul en M9.5 podrían estar reprimidos o simplemente menos expresados.Este tipo de visualización puede ayudar a identificar subconjuntos de genes específicos de cada condición, que podrían ser relevantes en los procesos biológicos o en las etapas de desarrollo representadas por M9.5 y M10.5.
write.csv(as.data.frame(res), file = "resultados_expresion_diferencial_completo.csv", row.names = TRUE)
write.csv(as.data.frame(res), file = "resultados_expresion_diferencial_filtrados.csv", row.names = TRUE)