En esta sección, se importa y organiza la información de los datos de expresión diferencial, estableciendo una base para el análisis posterior. Esto incluye la lectura de los archivos de datos, la creación de un objeto adecuado para el análisis y la asignación de los nombres de las muestras y grupos experimentales.
Se importan los datos de expresión diferencial en R utilizando el paquete edgeR. Este código se encarga de leer los datos desde archivos y almacenarlos en un objeto adecuado para su posterior análisis.
Código
### Importamos los datos al objeto DGE##### Del primer fichero se leen las primeras cinco filas para inspeccionar la estructura del archivo ###knitr::kable(read.delim(files[1], nrow=5))
EntrezID
GeneLength
Count
497097
3634
1
100503874
3259
0
100038431
1634
0
19888
9747
0
20671
3130
1
Código
## Se crea el objeto DGEList con todos los archivos y se incluye toda la información necesaria, como el nombre de muestra y el grupo al que pertenece (factor) ###x <-readDGE(files, columns=c(1,3))## Se inspecciona el objeto DGEList para confirmar su correcta creación ###knitr::kable(x$samples)
files
group
lib.size
norm.factors
GSM1545535_10_6_5_11
GSM1545535_10_6_5_11.txt
1
32863052
1
GSM1545536_9_6_5_11
GSM1545536_9_6_5_11.txt
1
35335491
1
GSM1545538_purep53
GSM1545538_purep53.txt
1
57160817
1
GSM1545539_JMS8-2
GSM1545539_JMS8-2.txt
1
51368625
1
GSM1545540_JMS8-3
GSM1545540_JMS8-3.txt
1
75795034
1
GSM1545541_JMS8-4
GSM1545541_JMS8-4.txt
1
60517657
1
GSM1545542_JMS8-5
GSM1545542_JMS8-5.txt
1
55086324
1
GSM1545544_JMS9-P7c
GSM1545544_JMS9-P7c.txt
1
21311068
1
GSM1545545_JMS9-P8c
GSM1545545_JMS9-P8c.txt
1
19958838
1
En este código, se realiza la lectura preliminar de las primeras cinco filas del primer archivo para comprender su estructura. Luego, se utiliza la función readDGE para crear un objeto DGEList que contiene los datos de todos los archivos especificados en la variable files, incluyendo las columnas que contienen los identificadores de las muestras y los valores de expresión. Finalmente, se inspecciona el objeto DGEList creado para verificar su tipo, dimensiones y contenido.
Posteriormente, se organiza la información del diseño experimental para preparar los datos de expresión diferencial para su análisis en R. Este código se encarga de extraer y asignar nombres de muestras y de definir los grupos experimentales a los que pertenecen las muestras.
Código
### Organizamos la información del diseño experimental ##### Se extraen los nombres de las muestras eliminando caracteres innecesarios de los nombres de las columnas ###samplenames <-substring(colnames(x), 12, nchar(colnames(x)))## Se actualizan los nombres de las columnas del objeto con los nombres de las muestras ###colnames(x) <- samplenames## Se crea un factor que representa las condiciones experimentales de cada muestra ###group <-as.factor(c("LP", "ML", "Basal","Basal", "ML", "LP","Basal", "ML", "LP"))## Se incorpora la información de las condiciones experimentales en el objeto DGEList ###x$samples$group <- groupknitr::kable(x$samples)
files
group
lib.size
norm.factors
10_6_5_11
GSM1545535_10_6_5_11.txt
LP
32863052
1
9_6_5_11
GSM1545536_9_6_5_11.txt
ML
35335491
1
purep53
GSM1545538_purep53.txt
Basal
57160817
1
JMS8-2
GSM1545539_JMS8-2.txt
Basal
51368625
1
JMS8-3
GSM1545540_JMS8-3.txt
ML
75795034
1
JMS8-4
GSM1545541_JMS8-4.txt
LP
60517657
1
JMS8-5
GSM1545542_JMS8-5.txt
Basal
55086324
1
JMS9-P7c
GSM1545544_JMS9-P7c.txt
ML
21311068
1
JMS9-P8c
GSM1545545_JMS9-P8c.txt
LP
19958838
1
En el código superior, se procesan los nombres de las muestras al eliminar caracteres innecesarios, asignando nombres claros y concisos a las columnas del objeto DGEList. Luego, se crea un factor que indica a qué grupo experimental pertenece cada muestra. Finalmente, se añade esta información de los grupos experimentales al objeto DGEList, integrando así todos los datos necesarios para el análisis.
2 Anotación Génica y Transformación de los Datos de Expresión
En esta sección, se añade información de anotación génica a los datos de expresión y se transforman las lecturas a cuentas por millón (CPM), en base logarítmica. Adicionalmente, se filtran los genes con baja expresión para asegurar que solo los genes relevantes sean considerados en el análisis y se generan representaciones gráficas de las cuentas por millón (CPM) antes y después del filtrado para visualizar y comparar la distribución de los datos de expresión.
Primero se incorpora un fichero de anotación génica para aportar información adicional sobre los genes a los datos de expresión diferencial. Este código se encarga de crear objetos con los identificadores y nombres de los genes, y de eliminar duplicados para asegurar la unicidad de los IDs.
Código
### Incorporamos fichero de anotación génica ##### Se crea un objeto que contiene los IDs de los genes a partir de las filas del objeto DGEList ###geneid <-rownames(x)knitr::kable(head(geneid))
x
497097
100503874
100038431
19888
20671
27395
Código
## Se crea un objeto que contiene los nombres de los genes y su cromosoma utilizando el paquete Mus.musculus ###genes <-select(Mus.musculus, keys=geneid, columns=c("SYMBOL", "TXCHROM"), keytype="ENTREZID")knitr::kable(head(genes))
ENTREZID
SYMBOL
TXCHROM
497097
Xkr4
chr1
100503874
Gm19938
NA
100038431
Gm10568
NA
19888
Rp1
chr1
20671
Sox17
chr1
27395
Mrpl15
chr1
Código
## Se eliminan los genes duplicados para asegurar que cada ID de gen sea único ###genes <- genes[!duplicated(genes$ENTREZID),]## Se incorpora la anotación génica al objeto DGEList ###x$genes <- genesknitr::kable(x$samples)
files
group
lib.size
norm.factors
10_6_5_11
GSM1545535_10_6_5_11.txt
LP
32863052
1
9_6_5_11
GSM1545536_9_6_5_11.txt
ML
35335491
1
purep53
GSM1545538_purep53.txt
Basal
57160817
1
JMS8-2
GSM1545539_JMS8-2.txt
Basal
51368625
1
JMS8-3
GSM1545540_JMS8-3.txt
ML
75795034
1
JMS8-4
GSM1545541_JMS8-4.txt
LP
60517657
1
JMS8-5
GSM1545542_JMS8-5.txt
Basal
55086324
1
JMS9-P7c
GSM1545544_JMS9-P7c.txt
ML
21311068
1
JMS9-P8c
GSM1545545_JMS9-P8c.txt
LP
19958838
1
En este código, se extraen los identificadores de los genes de las filas del objeto DGEList y se almacenan en un nuevo objeto. Luego, se utiliza la función select del paquete Mus.musculus para obtener los nombres y los cromosomas de los genes asociados a estos identificadores. Los duplicados se eliminan para asegurar que cada identificador de gen sea único. Finalmente, se integra esta información de anotación génica en el objeto DGEList, enriqueciendo los datos de expresión con información adicional sobre los genes.
Se transforman las lecturas mapeadas a cuentas por millón (CPM) y se filtran los genes con baja expresión para preparar los datos de expresión diferencial para un análisis más preciso.
Código
## Transformamos las lecturas mapeadas a cuentas por millón, también en base logarítmica ###cpm.raw <-cpm(x)lcpm.raw <-cpm(x, log=TRUE)## Se cuentan los genes que no tienen valor de expresión en ninguna de las muestras ###knitr::kable(table(rowSums(x$counts ==0) ==9))
Var1
Freq
FALSE
22026
TRUE
5153
Código
## Se filtran los genes con baja expresión, manteniendo aquellos que tienen una expresión mayor a 1 CPM en al menos 3 muestras ###keep.exprs <-rowSums(cpm.raw >1) >=3x.filt <- x[keep.exprs, , keep.lib.sizes=FALSE]## Se muestran las dimensiones del objeto filtrado ###print(paste("Dimensiones del objeto filtrado:", sep=" "))
[1] "Dimensiones del objeto filtrado:"
Código
print(dim(x.filt))
[1] 14165 9
En este código, se transforman las lecturas de los datos de expresión a cuentas por millón (CPM) y se calculan también en escala logarítmica para normalizar los datos. Luego, se cuenta el número de genes que no tienen ningún valor de expresión en todas las muestras. Para mejorar la calidad del análisis, se filtran los genes con baja expresión, reteniendo solo aquellos genes que tienen una expresión mayor a 1 CPM en al menos tres muestras. Finalmente, se verifica la cantidad de genes y muestras en el objeto filtrado x.filt para asegurarse de que el filtrado se haya realizado correctamente.
Código
### Representación gráfica de las cpm antes y después de filtrar ###dev.new()nsamples <-ncol(x.filt)col <-brewer.pal(nsamples, "Paired")# Gráfica para los datos en brutopar(mfrow=c(1,1))
Gráficas 2.1: Comparación de la Distribución de CPM en Datos en Bruto y Filtrados
Código
plot(density(lcpm.raw[,1]), col=col[1], lwd=2, ylim=c(0,0.21), las=2,main="", xlab="", ylab="Densidad")title(main="A. Datos en bruto", xlab="Log-cpm") # Se cambia el nombre por defecto del eje Yabline(v=0, lty=3) # Se marca el umbral del filtradofor (i in2:nsamples){ den <-density(lcpm.raw[,i])lines(den$x, den$y, col=col[i], lwd=2)}legend("topright", samplenames, text.col=col, bty="n")
Código
# Gráfico con los datos filtradoslcpm.filt <-cpm(x.filt, log=TRUE)plot(density(lcpm.filt[,1]), col=col[1], lwd=2, ylim=c(0,0.21), las=2,main="", xlab="", ylab="")title(main="B. Filtrado", xlab="Log-cpm", ylab="Densidad") # Se cambia el nombre por defecto del eje Yabline(v=0, lty=3) # Se marca el umbral del filtradofor (i in2:nsamples){ den <-density(lcpm.filt[,i])lines(den$x, den$y, col=col[i], lwd=2)}legend("topright", samplenames, text.col=col, bty="n")
Las Gráficas 2.1, presentan dos gráficos de densidad que muestran la distribución de las cuentas por millón (CPM) en escala logarítmica antes (superior, A. Datos en bruto) y después (inferior, B. Filtrado) del filtrado de genes con baja expresión.
En el panel A, que representa los datos en bruto, se observa una alta densidad de valores de expresión cercanos a cero, indicando la presencia de muchos genes con baja o nula expresión en las muestras. Después del filtrado, en el panel B, la distribución se vuelve más uniforme y centrada, eliminando la mayoría de los genes con baja expresión. Este proceso de filtrado mejora la calidad de los datos al excluir genes no informativos, permitiendo un análisis más robusto de la expresión diferencial.
La leyenda en ambos gráficos identifica las muestras, coloreadas para facilitar la comparación visual. La línea vertical punteada en ambos gráficos marca el umbral de filtrado, mostrando que el filtrado ha removido adecuadamente los genes con valores de CPM por debajo de este umbral.
2.1 Normalización de los Datos
Se normalizan los datos de expresión para ajustar las diferencias en la profundidad de secuenciación entre las muestras. Además, se representa gráficamente la distribución de los factores de normalización para evaluar la eficacia del proceso de normalización.
Código
### Normalización de datos de expresión ##### Se calculan los factores de normalización utilizando el método TMM (Trimmed Mean of M-values) ###x.norm <-calcNormFactors(x.filt, method ="TMM")## Se muestran los factores de normalización calculados para cada muestra ###x.norm$samples$norm.factors
### Representación de los factores de normalización ###dev.new()par(mfrow=c(1,2))
Gráficas 2.2: Boxplot de Factores de Normalización
Código
## Se crea un boxplot de los factores de normalización para todas las muestras ###boxplot(x.norm$samples$norm.factors, xlab="Todas las muestras", ylab="Valor de norm.factors", main="Distribución de todos los norm.factors")
Código
## Se crea un boxplot de los factores de normalización para cada muestra individualmente ###boxplot(x.norm$samples$norm.factors ~rownames(x.norm$samples), ylab="Valor de norm.factors", main="B. Norm.factors por muestra", las=2)## Se añade una línea horizontal que marca el valor 1.0, indicando el valor de referencia para los factores de normalización ###abline(h=1.0, lty=3)
En este código, se realiza la normalización de los datos de expresión utilizando el método TMM (Trimmed Mean of M-values), que ajusta las diferencias en la profundidad de secuenciación entre las muestras para obtener datos comparables. Los factores de normalización calculados para cada muestra se muestran para verificar que la normalización se ha aplicado correctamente. Luego, se generan dos gráficos de caja (boxplots) para representar la distribución de estos factores de normalización. El primer gráfico muestra la distribución de los factores de normalización para todas las muestras en conjunto, mientras que el segundo gráfico presenta estos factores para cada muestra individualmente, facilitando la identificación de posibles discrepancias.
Se representan gráficamente los datos de expresión en estado bruto y después de la normalización para comparar la distribución de los datos. Además, se generan gráficos MDS (Multidimensional Scaling) para visualizar las relaciones entre las muestras antes y después del filtrado y la normalización.
## Boxplot de los datos en bruto ###boxplot(lcpm.raw, las=2, col=col, main="")title(main="A. Datos brutos", ylab="Log-cpm")
Código
## Boxplot de los datos normalizados ###lcpm.norm <-cpm(x.norm, log=TRUE)boxplot(lcpm.norm, las=2, col=col, main="")title(main="B. Datos normalizados", ylab="Log-cpm")
Comparando las Gráficas 2.3 y 2.4, se puede concluir que los boxplots muestran que las distribuciones de las CPM logarítmicas son más consistentes entre las muestras después de la normalización en comparación con los datos en bruto. Esta uniformidad indica que la normalización ha ajustado eficazmente las diferencias en la profundidad de secuenciación, mejorando la comparabilidad de los datos de expresión entre las muestras. Además, la presencia de más valores atípicos en los datos normalizados sugiere una mayor precisión en la detección de variaciones genuinas en los niveles de expresión génica.
Código
### Gráficos MDS para datos brutos, filtrados y normalizados ###dev.new()par(mfrow=c(1,3))## Definición de colores por grupo experimental ###col.group <- grouplevels(col.group) <-brewer.pal(nlevels(col.group), "Set1")col.group <-as.character(col.group)
## Gráfico MDS para datos en bruto ###plotMDS(lcpm.raw, labels=group, col=col.group)title(main="Raw: by sample groups")
Código
## Gráfico MDS para datos filtrados ###plotMDS(lcpm.filt, labels=group, col=col.group)title(main="Filtered: by sample groups")
Código
## Gráfico MDS para datos normalizados ###plotMDS(lcpm.norm, labels=group, col=col.group)title(main="Normalised: by sample groups")
En la Gráfica 2.5 (Raw: by sample groups), se observa que las muestras presentan una dispersión significativa, indicando variabilidad en las lecturas originales sin ningún procesamiento adicional. En la Gráfica 2.6 (Filtered: by sample groups), después del filtrado de genes con baja expresión, las muestras muestran una agrupación más clara, reflejando una reducción en el ruido de los datos. Finalmente, en la Gráfica 2.7 (Normalised: by sample groups), tras la normalización, las muestras se agrupan más estrechamente dentro de sus respectivos grupos experimentales. Esta progresión desde los datos en bruto hasta los datos normalizados evidencia cómo el filtrado y la normalización mejoran la claridad y precisión de la discriminación entre los grupos experimentales, permitiendo un análisis diferencial más robusto.
3 Diseño Experimental y Comparaciones
Se establece el diseño experimental para el análisis diferencial de expresión y se definen las comparaciones específicas a realizar entre los grupos experimentales. Esto incluye la creación de una matriz de diseño y una matriz de contrastes que especifica las comparaciones de interés.
Código
### Diseño experimental ##### Se crea la matriz de diseño basada en los grupos experimentales ###design <-model.matrix(~0+ group)## Se simplifican los nombres de las columnas eliminando el prefijo "group" ###colnames(design) <-gsub("group", "", colnames(design))design
### Comparaciones a realizar ##### Se crea una matriz de contrastes para especificar las comparaciones entre los grupos experimentales ###contr.matrix <-makeContrasts(BasalvsLP = Basal - LP,BasalvsML = Basal - ML,LPvsML = LP - ML,levels =colnames(design))contr.matrix
Se establece el diseño experimental creando una matriz de diseño que incluye los grupos experimentales, eliminando el prefijo “group” de los nombres de las columnas para simplificar. Posteriormente, se define una matriz de contrastes que especifica las comparaciones a realizar entre los grupos experimentales: “Basal” versus “LP”, “Basal” versus “ML” y “LP” versus “ML”.
Se aplican modificaciones al modelo lineal para analizar los datos de expresión diferencial utilizando el método voom del paquete limma. Este proceso incluye la transformación de los datos en bruto y normalizados, así como la aplicación de ajustes de modelos lineales y el análisis bayesiano para determinar la significancia de las comparaciones.
# Transformación de datos en bruto utilizando voomv.raw <-voom(x, design, plot=TRUE)title(sub="Datos brutos")
Código
# Transformación de datos normalizados utilizando voomv.norm <-voom(x.norm, design, plot=TRUE)title(sub="Datos filtrados y normalizados")
En la Gráfica 3.1 (Datos brutos), se observa una tendencia decreciente en la relación entre la media y la varianza de los datos de expresión, con una alta dispersión en las desviaciones estándar para los valores de cuenta más bajos. Esto indica una gran variabilidad en los datos en bruto. Por otro lado, en la Gráfica 3.2 (Datos filtrados y normalizados), la tendencia media-varianza muestra una relación más estable y ajustada, con una menor dispersión en las desviaciones estándar, especialmente para los valores de cuenta intermedios y altos. La reducción de la variabilidad después del filtrado y la normalización sugiere que estos pasos han mejorado la calidad de los datos.
Código
### Comparación en el modelo lineal #### Ajuste del modelo lineal para datos en brutovfit.raw <-lmFit(v.raw, design)vfit.raw <-contrasts.fit(vfit.raw, contrasts=contr.matrix)efit.raw <-eBayes(vfit.raw)# Ajuste del modelo lineal para datos normalizadosvfit.norm <-lmFit(v.norm, design)vfit.norm <-contrasts.fit(vfit.norm, contrasts=contr.matrix)efit.norm <-eBayes(vfit.norm)
Se han realizado entonces varias etapas de análisis para permitir identificar los genes diferencialmente expresados entre los diversos grupos experimentales.:
Transformación con voom: Se transforman los datos en bruto y normalizados utilizando el método voom, que ajusta la media-variancia de los datos para hacerlos aptos para el análisis lineal. Se generan gráficos de los datos transformados para visualización.
Ajuste del modelo lineal: Se aplica el modelo lineal a los datos transformados, tanto en bruto como normalizados. Esto se hace mediante la función lmFit que ajusta el modelo lineal a los datos.
Contrastes y ajuste bayesiano: Se aplican los contrastes especificados en la matriz de contrastes utilizando contrasts.fit, y luego se realiza un ajuste bayesiano con eBayes para determinar la significancia estadística de las comparaciones entre los grupos experimentales.
Se va a proceder inspeccionando la normalización de los datos de expresión diferencial mediante la visualización de la relación media-varianza utilizando el modelo final ajustado.
# Datos brutosplotSA(efit.raw, main="Final model: Mean−variance trend")title(sub="Datos brutos")
Código
# Datos normalizadosplotSA(efit.norm, main="Final model: Mean−variance trend")title(sub="Datos filtrados y normalizados")
En las Gráficas 3.3 y 3.4, se compara la tendencia media-varianza para los datos en bruto y los datos filtrados y normalizados, respectivamente. La Gráfica 3.3 muestra una considerable dispersión en la desviación estándar en función de la expresión media logarítmica, con muchos puntos desviándose significativamente de la línea de referencia de 1.0, especialmente en los valores de expresión más bajos y más altos. Esto indica una gran variabilidad inherente en los datos originales. En contraste, la Gráfica 3.4 presenta una dispersión mucho menor y más consistente a lo largo de diferentes niveles de expresión media logarítmica, con la mayoría de los puntos más cercanos a la línea de referencia de 1.0. Esta menor variabilidad después del filtrado y la normalización sugiere que estos pasos han mejorado significativamente la calidad de los datos, haciendo que las mediciones de expresión sean más comparables y precisas para el análisis diferencial.
4 Test de Múltiples Comparaciones
Finalmente, se utilizará este código para identificar y resumir el número de genes expresados diferencialmente en diferentes comparaciones basadas en el valor p y el cambio de pliegue logarítmico (logFC) en datos normalizados y en datos en bruto.
### Esta función muestra el número de genes que se expresa de forma diferencial por pvalue en cada comparación #### Sobre los datos normalizadosknitr::kable(summary(decideTests(efit.norm)))
BasalvsLP
BasalvsML
LPvsML
Down
4019
4312
2490
NotSig
5859
5595
9639
Up
4287
4258
2036
Código
# Sobre los datos brutosknitr::kable(summary(decideTests(efit.raw)))
BasalvsLP
BasalvsML
LPvsML
Down
3877
5004
3472
NotSig
17519
17182
22163
Up
5783
4993
1544
Código
### Otro filtro muy utilizado es las veces de cambio en base logarítmica, logFC #### lfc: logarithm of fold change; 1 significa un FC 2^1 = 2# treat() es una función alternativa a eBayes() para tener en cuenta el logFCtfit <-treat(vfit.norm, lfc=1)dt <-decideTests(tfit)knitr::kable(summary(dt))
BasalvsLP
BasalvsML
LPvsML
Down
1298
1455
152
NotSig
11153
10917
13899
Up
1714
1793
114
Código
# Veamos lo mismo con los datos sin filtrar ni normalizartfit.raw <-treat(vfit.raw, lfc=1)dt.raw <-decideTests(tfit.raw)knitr::kable(summary(dt.raw))
BasalvsLP
BasalvsML
LPvsML
Down
1397
1779
277
NotSig
23539
23229
26792
Up
2243
2171
110
En este código, se realizan las siguientes acciones:
Identificación de genes expresados diferencialmente por valor p:
Datos normalizados: Se utiliza la función decideTests sobre el objeto efit.norm para identificar los genes que se expresan de forma diferencial en las comparaciones especificadas en la matriz de diseño. El resumen de estos resultados se muestra con summary.
Datos brutos: Se realiza el mismo procedimiento sobre los datos en bruto utilizando el objeto efit.raw.
Filtrado por cambio de pliegue logarítmico (logFC):
Datos normalizados: Se utiliza la función treat en lugar de eBayes para tener en cuenta el logFC. Un logFC de 1 significa un cambio de pliegue de 2^1 = 2. El objeto resultante tfit se pasa a decideTests para identificar los genes diferencialmente expresados, y se muestra un resumen de estos resultados.
Datos brutos: Se repite el mismo procedimiento para los datos en bruto utilizando el objeto vfit.raw.
Finalmente, se va a proceder a comparar la expresión diferencial de genes entre las condiciones “BasalvsLP” y “BasalvsML”, identificándose la intersección de genes diferencialmente expresados en ambas comparaciones, y se visualizan y guardan los resultados.
# Dibujamos un diagrama de Venn para representar las comparacionesvennDiagram(dt[,1:2], circle.col=c("turquoise", "salmon"))
El diagrama de Venn muestra la comparación de genes con expresión diferencial entre las condiciones “BasalvsLP” y “BasalvsML”. En este diagrama, el círculo izquierdo representa los genes diferencialmente expresados en la comparación “BasalvsLP”, mientras que el círculo derecho representa los genes diferencialmente expresados en la comparación “BasalvsML”. Se observa que 672 genes son exclusivos de la comparación “BasalvsLP”, 908 genes son exclusivos de la comparación “BasalvsML”, y 2340 genes son comunes a ambas comparaciones. El número total de genes analizados es 10245. Estos resultados indican que hay una considerable superposición de genes con expresión diferencial entre las dos condiciones comparadas, lo que sugiere que existen cambios comunes en la expresión génica cuando se comparan las condiciones Basal con LP y Basal con ML.
Código
### Comparamos los genes con expresión diferencial entre las condiciones BasalvsLP y BasalvsML #### Identificación de genes expresados diferencialmente en ambas comparacionesde.common <-which(dt[,1] !=0& dt[,2] !=0)# ¿Cuántos son?length(de.common)
[1] 2340
Código
# ¿Cómo se llaman los 20 primeros?head(tfit$genes$SYMBOL[de.common], n=20)
### Escribimos los resultados ###write.fit(tfit, dt, file="all_genes_results.txt")
En este código, se realizan las siguientes acciones:
Identificación de genes con expresión diferencial común:
Se determina qué genes están expresados diferencialmente en ambas comparaciones (“BasalvsLP” y “BasalvsML”) utilizando la función which y la condición dt[,1] != 0 & dt[,2] != 0. Los índices de estos genes se almacenan en de.common.
Conteo y visualización de genes:
Se cuenta el número de genes en común utilizando length(de.common).
Se muestran los nombres de los primeros 20 genes comunes utilizando head(tfit$genes$SYMBOL[de.common], n=20).
Visualización con diagrama de Venn:
Se genera un diagrama de Venn para representar visualmente la superposición de genes expresados diferencialmente en las dos comparaciones.
Ejecutar el código
---title: "Análisis de Expresión Diferencial"author: "Mario Pascual González"format: html: theme: light: flatly dark: darkly highlight-style: monokai toc: true toc-depth: 3 toc-title: Contenidos toc-float: collapsed: false smooth-scroll: true toc_scroll: true number-sections: true code-fold: true code-tools: source: true toggle: true caption: Expand Code html-math-method: katex bibliography: references.bib lang: es other-links: - text: LinkedIn icon: linkedin href: "https://www.linkedin.com/in/mario-pascual-gonzalez/" - text: Correo Electrónico icon: envelope href: mailto:mario.pg02@gmail.com?subject=Contacto desde el informe de Modelado Predictivo - text: Perfil de Github icon: github href: https://github.com/MarioPascresource_files:- references.bib- Variables.png---```{r setup, echo=FALSE, message=FALSE, warning=FALSE}#| output: false#| echo: false#| warning: falselibrary(limma)library(Glimma)library(edgeR)library(VennDiagram)library(Mus.musculus)library(RColorBrewer)library(gplots)url <- "http://www.ncbi.nlm.nih.gov/geo/download/?acc=GSE63310&format=file"utils::download.file(url, destfile="GSE63310_RAW.tar", mode="wb")utils::untar("GSE63310_RAW.tar", exdir = ".")files <- c("GSM1545535_10_6_5_11.txt", "GSM1545536_9_6_5_11.txt","GSM1545538_purep53.txt","GSM1545539_JMS8-2.txt", "GSM1545540_JMS8-3.txt","GSM1545541_JMS8-4.txt","GSM1545542_JMS8-5.txt", "GSM1545544_JMS9-P7c.txt","GSM1545545_JMS9-P8c.txt")for(i in paste(files, ".gz", sep="")) { R.utils::gunzip(i, overwrite=TRUE)}```# Datos y Directorio de TrabajoEn esta sección, se importa y organiza la información de los datos de expresión diferencial, estableciendo una base para el análisis posterior. Esto incluye la lectura de los archivos de datos, la creación de un objeto adecuado para el análisis y la asignación de los nombres de las muestras y grupos experimentales.Se importan los datos de expresión diferencial en R utilizando el paquete `edgeR`. Este código se encarga de leer los datos desde archivos y almacenarlos en un objeto adecuado para su posterior análisis.```{r}### Importamos los datos al objeto DGE##### Del primer fichero se leen las primeras cinco filas para inspeccionar la estructura del archivo ###knitr::kable(read.delim(files[1], nrow=5))## Se crea el objeto DGEList con todos los archivos y se incluye toda la información necesaria, como el nombre de muestra y el grupo al que pertenece (factor) ###x <-readDGE(files, columns=c(1,3))## Se inspecciona el objeto DGEList para confirmar su correcta creación ###knitr::kable(x$samples)```En este código, se realiza la lectura preliminar de las primeras cinco filas del primer archivo para comprender su estructura. Luego, se utiliza la función `readDGE` para crear un objeto `DGEList` que contiene los datos de todos los archivos especificados en la variable `files`, incluyendo las columnas que contienen los identificadores de las muestras y los valores de expresión. Finalmente, se inspecciona el objeto `DGEList` creado para verificar su tipo, dimensiones y contenido.Posteriormente, se organiza la información del diseño experimental para preparar los datos de expresión diferencial para su análisis en R. Este código se encarga de extraer y asignar nombres de muestras y de definir los grupos experimentales a los que pertenecen las muestras.```{r}### Organizamos la información del diseño experimental ##### Se extraen los nombres de las muestras eliminando caracteres innecesarios de los nombres de las columnas ###samplenames <-substring(colnames(x), 12, nchar(colnames(x)))## Se actualizan los nombres de las columnas del objeto con los nombres de las muestras ###colnames(x) <- samplenames## Se crea un factor que representa las condiciones experimentales de cada muestra ###group <-as.factor(c("LP", "ML", "Basal","Basal", "ML", "LP","Basal", "ML", "LP"))## Se incorpora la información de las condiciones experimentales en el objeto DGEList ###x$samples$group <- groupknitr::kable(x$samples)```En el código superior, se procesan los nombres de las muestras al eliminar caracteres innecesarios, asignando nombres claros y concisos a las columnas del objeto `DGEList`. Luego, se crea un factor que indica a qué grupo experimental pertenece cada muestra. Finalmente, se añade esta información de los grupos experimentales al objeto `DGEList`, integrando así todos los datos necesarios para el análisis.# Anotación Génica y Transformación de los Datos de Expresión En esta sección, se añade información de anotación génica a los datos de expresión y se transforman las lecturas a cuentas por millón (CPM), en base logarítmica. Adicionalmente, se filtran los genes con baja expresión para asegurar que solo los genes relevantes sean considerados en el análisis y se generan representaciones gráficas de las cuentas por millón (CPM) antes y después del filtrado para visualizar y comparar la distribución de los datos de expresión. Primero se incorpora un fichero de anotación génica para aportar información adicional sobre los genes a los datos de expresión diferencial. Este código se encarga de crear objetos con los identificadores y nombres de los genes, y de eliminar duplicados para asegurar la unicidad de los IDs.```{r, message=FALSE, warning=FALSE}### Incorporamos fichero de anotación génica ##### Se crea un objeto que contiene los IDs de los genes a partir de las filas del objeto DGEList ###geneid <- rownames(x)knitr::kable(head(geneid))## Se crea un objeto que contiene los nombres de los genes y su cromosoma utilizando el paquete Mus.musculus ###genes <- select(Mus.musculus, keys=geneid, columns=c("SYMBOL", "TXCHROM"), keytype="ENTREZID")knitr::kable(head(genes))## Se eliminan los genes duplicados para asegurar que cada ID de gen sea único ###genes <- genes[!duplicated(genes$ENTREZID),]## Se incorpora la anotación génica al objeto DGEList ###x$genes <- genesknitr::kable(x$samples)```En este código, se extraen los identificadores de los genes de las filas del objeto `DGEList` y se almacenan en un nuevo objeto. Luego, se utiliza la función `select` del paquete `Mus.musculus` para obtener los nombres y los cromosomas de los genes asociados a estos identificadores. Los duplicados se eliminan para asegurar que cada identificador de gen sea único. Finalmente, se integra esta información de anotación génica en el objeto `DGEList`, enriqueciendo los datos de expresión con información adicional sobre los genes.Se transforman las lecturas mapeadas a cuentas por millón (CPM) y se filtran los genes con baja expresión para preparar los datos de expresión diferencial para un análisis más preciso.```{r}## Transformamos las lecturas mapeadas a cuentas por millón, también en base logarítmica ###cpm.raw <-cpm(x)lcpm.raw <-cpm(x, log=TRUE)## Se cuentan los genes que no tienen valor de expresión en ninguna de las muestras ###knitr::kable(table(rowSums(x$counts ==0) ==9))## Se filtran los genes con baja expresión, manteniendo aquellos que tienen una expresión mayor a 1 CPM en al menos 3 muestras ###keep.exprs <-rowSums(cpm.raw >1) >=3x.filt <- x[keep.exprs, , keep.lib.sizes=FALSE]## Se muestran las dimensiones del objeto filtrado ###print(paste("Dimensiones del objeto filtrado:", sep=" "))print(dim(x.filt))```En este código, se transforman las lecturas de los datos de expresión a cuentas por millón (CPM) y se calculan también en escala logarítmica para normalizar los datos. Luego, se cuenta el número de genes que no tienen ningún valor de expresión en todas las muestras. Para mejorar la calidad del análisis, se filtran los genes con baja expresión, reteniendo solo aquellos genes que tienen una expresión mayor a 1 CPM en al menos tres muestras. Finalmente, se verifica la cantidad de genes y muestras en el objeto filtrado `x.filt` para asegurarse de que el filtrado se haya realizado correctamente.```{r}### Representación gráfica de las cpm antes y después de filtrar ###dev.new()nsamples <-ncol(x.filt)col <-brewer.pal(nsamples, "Paired")# Gráfica para los datos en brutopar(mfrow=c(1,1))```### Gráficas 2.1: Comparación de la Distribución de CPM en Datos en Bruto y Filtrados {-}```{r}plot(density(lcpm.raw[,1]), col=col[1], lwd=2, ylim=c(0,0.21), las=2,main="", xlab="", ylab="Densidad")title(main="A. Datos en bruto", xlab="Log-cpm") # Se cambia el nombre por defecto del eje Yabline(v=0, lty=3) # Se marca el umbral del filtradofor (i in2:nsamples){ den <-density(lcpm.raw[,i])lines(den$x, den$y, col=col[i], lwd=2)}legend("topright", samplenames, text.col=col, bty="n")``````{r}# Gráfico con los datos filtradoslcpm.filt <-cpm(x.filt, log=TRUE)plot(density(lcpm.filt[,1]), col=col[1], lwd=2, ylim=c(0,0.21), las=2,main="", xlab="", ylab="")title(main="B. Filtrado", xlab="Log-cpm", ylab="Densidad") # Se cambia el nombre por defecto del eje Yabline(v=0, lty=3) # Se marca el umbral del filtradofor (i in2:nsamples){ den <-density(lcpm.filt[,i])lines(den$x, den$y, col=col[i], lwd=2)}legend("topright", samplenames, text.col=col, bty="n")```Las **Gráficas 2.1**, presentan dos gráficos de densidad que muestran la distribución de las cuentas por millón (CPM) en escala logarítmica antes (superior, A. Datos en bruto) y después (inferior, B. Filtrado) del filtrado de genes con baja expresión. En el panel A, que representa los datos en bruto, se observa una alta densidad de valores de expresión cercanos a cero, indicando la presencia de muchos genes con baja o nula expresión en las muestras. Después del filtrado, en el panel B, la distribución se vuelve más uniforme y centrada, eliminando la mayoría de los genes con baja expresión. Este proceso de filtrado mejora la calidad de los datos al excluir genes no informativos, permitiendo un análisis más robusto de la expresión diferencial. La leyenda en ambos gráficos identifica las muestras, coloreadas para facilitar la comparación visual. La línea vertical punteada en ambos gráficos marca el umbral de filtrado, mostrando que el filtrado ha removido adecuadamente los genes con valores de CPM por debajo de este umbral.## Normalización de los DatosSe normalizan los datos de expresión para ajustar las diferencias en la profundidad de secuenciación entre las muestras. Además, se representa gráficamente la distribución de los factores de normalización para evaluar la eficacia del proceso de normalización.```{r}### Normalización de datos de expresión ##### Se calculan los factores de normalización utilizando el método TMM (Trimmed Mean of M-values) ###x.norm <-calcNormFactors(x.filt, method ="TMM")## Se muestran los factores de normalización calculados para cada muestra ###x.norm$samples$norm.factors### Representación de los factores de normalización ###dev.new()par(mfrow=c(1,2))```### Gráficas 2.2: Boxplot de Factores de Normalización {-}```{r}## Se crea un boxplot de los factores de normalización para todas las muestras ###boxplot(x.norm$samples$norm.factors, xlab="Todas las muestras", ylab="Valor de norm.factors", main="Distribución de todos los norm.factors")``````{r}## Se crea un boxplot de los factores de normalización para cada muestra individualmente ###boxplot(x.norm$samples$norm.factors ~rownames(x.norm$samples), ylab="Valor de norm.factors", main="B. Norm.factors por muestra", las=2)## Se añade una línea horizontal que marca el valor 1.0, indicando el valor de referencia para los factores de normalización ###abline(h=1.0, lty=3)```En este código, se realiza la normalización de los datos de expresión utilizando el método **TMM (Trimmed Mean of M-values)**, que ajusta las diferencias en la profundidad de secuenciación entre las muestras para obtener datos comparables. Los factores de normalización calculados para cada muestra se muestran para verificar que la normalización se ha aplicado correctamente. Luego, se generan dos gráficos de caja (boxplots) para representar la distribución de estos factores de normalización. El primer gráfico muestra la distribución de los factores de normalización para todas las muestras en conjunto, mientras que el segundo gráfico presenta estos factores para cada muestra individualmente, facilitando la identificación de posibles discrepancias. Se representan gráficamente los datos de expresión en estado bruto y después de la normalización para comparar la distribución de los datos. Además, se generan gráficos MDS (Multidimensional Scaling) para visualizar las relaciones entre las muestras antes y después del filtrado y la normalización.:::{.panel-tabset}## Gráfica 2.3: Log-CPM con Datos Brutos```{r}## Boxplot de los datos en bruto ###boxplot(lcpm.raw, las=2, col=col, main="")title(main="A. Datos brutos", ylab="Log-cpm")```## Gráfica 2.4: Log-CPM con Datos Normalizados```{r}## Boxplot de los datos normalizados ###lcpm.norm <-cpm(x.norm, log=TRUE)boxplot(lcpm.norm, las=2, col=col, main="")title(main="B. Datos normalizados", ylab="Log-cpm")```:::Comparando las Gráficas 2.3 y 2.4, se puede concluir que los boxplots muestran que las distribuciones de **las CPM logarítmicas son más consistentes entre las muestras después de la normalización en comparación con los datos en bruto**. Esta uniformidad indica que la normalización ha ajustado eficazmente las diferencias en la profundidad de secuenciación, mejorando la comparabilidad de los datos de expresión entre las muestras. Además, la presencia de más valores atípicos en los datos normalizados sugiere una mayor precisión en la detección de variaciones genuinas en los niveles de expresión génica.```{r}### Gráficos MDS para datos brutos, filtrados y normalizados ###dev.new()par(mfrow=c(1,3))## Definición de colores por grupo experimental ###col.group <- grouplevels(col.group) <-brewer.pal(nlevels(col.group), "Set1")col.group <-as.character(col.group)```:::{.panel-tabset}## Gráfica 2.5: MDS Raw```{r}## Gráfico MDS para datos en bruto ###plotMDS(lcpm.raw, labels=group, col=col.group)title(main="Raw: by sample groups")```## Gráfica 2.6: MDS Filtered```{r}## Gráfico MDS para datos filtrados ###plotMDS(lcpm.filt, labels=group, col=col.group)title(main="Filtered: by sample groups")```## Gráfica 2.7: MDS Normalized```{r}## Gráfico MDS para datos normalizados ###plotMDS(lcpm.norm, labels=group, col=col.group)title(main="Normalised: by sample groups")```:::En la Gráfica 2.5 (*Raw: by sample groups*), se observa que las muestras presentan una dispersión significativa, indicando variabilidad en las lecturas originales sin ningún procesamiento adicional. En la Gráfica 2.6 (*Filtered: by sample groups*), después del filtrado de genes con baja expresión, las muestras muestran una agrupación más clara, reflejando una reducción en el ruido de los datos. Finalmente, en la Gráfica 2.7 (*Normalised: by sample groups*), tras la normalización, las muestras se agrupan más estrechamente dentro de sus respectivos grupos experimentales. Esta progresión desde los datos en bruto hasta los datos normalizados evidencia cómo el filtrado y la normalización mejoran la claridad y precisión de la discriminación entre los grupos experimentales, permitiendo un análisis diferencial más robusto.# Diseño Experimental y ComparacionesSe establece el diseño experimental para el análisis diferencial de expresión y se definen las comparaciones específicas a realizar entre los grupos experimentales. Esto incluye la creación de una matriz de diseño y una matriz de contrastes que especifica las comparaciones de interés.```{r}### Diseño experimental ##### Se crea la matriz de diseño basada en los grupos experimentales ###design <-model.matrix(~0+ group)## Se simplifican los nombres de las columnas eliminando el prefijo "group" ###colnames(design) <-gsub("group", "", colnames(design))design### Comparaciones a realizar ##### Se crea una matriz de contrastes para especificar las comparaciones entre los grupos experimentales ###contr.matrix <-makeContrasts(BasalvsLP = Basal - LP,BasalvsML = Basal - ML,LPvsML = LP - ML,levels =colnames(design))contr.matrix```Se establece el diseño experimental creando una matriz de diseño que incluye los grupos experimentales, eliminando el prefijo "group" de los nombres de las columnas para simplificar. Posteriormente, se define una matriz de contrastes que especifica las comparaciones a realizar entre los grupos experimentales: "Basal" versus "LP", "Basal" versus "ML" y "LP" versus "ML". Se aplican modificaciones al modelo lineal para analizar los datos de expresión diferencial utilizando el método `voom` del paquete `limma`. Este proceso incluye la transformación de los datos en bruto y normalizados, así como la aplicación de ajustes de modelos lineales y el análisis bayesiano para determinar la significancia de las comparaciones.:::{.panel-tabset}## Gráfica 3.1: Mean-Variance Tren de Datos Brutos```{r}# Transformación de datos en bruto utilizando voomv.raw <-voom(x, design, plot=TRUE)title(sub="Datos brutos")```## Gráfica 3.2: Mean-Tariance Trend de Datos Filtrados y Normalizados```{r}# Transformación de datos normalizados utilizando voomv.norm <-voom(x.norm, design, plot=TRUE)title(sub="Datos filtrados y normalizados")```:::En la Gráfica 3.1 (Datos brutos), se observa una tendencia decreciente en la relación entre la media y la varianza de los datos de expresión, con una alta dispersión en las desviaciones estándar para los valores de cuenta más bajos. Esto indica una gran variabilidad en los datos en bruto. Por otro lado, en la Gráfica 3.2 (Datos filtrados y normalizados), la tendencia media-varianza muestra una relación más estable y ajustada, con una menor dispersión en las desviaciones estándar, especialmente para los valores de cuenta intermedios y altos. La reducción de la variabilidad después del filtrado y la normalización sugiere que estos pasos han mejorado la calidad de los datos.```{r}### Comparación en el modelo lineal #### Ajuste del modelo lineal para datos en brutovfit.raw <-lmFit(v.raw, design)vfit.raw <-contrasts.fit(vfit.raw, contrasts=contr.matrix)efit.raw <-eBayes(vfit.raw)# Ajuste del modelo lineal para datos normalizadosvfit.norm <-lmFit(v.norm, design)vfit.norm <-contrasts.fit(vfit.norm, contrasts=contr.matrix)efit.norm <-eBayes(vfit.norm)```Se han realizado entonces varias etapas de análisis para permitir identificar los genes diferencialmente expresados entre los diversos grupos experimentales.:1. **Transformación con `voom`**: Se transforman los datos en bruto y normalizados utilizando el método `voom`, que ajusta la media-variancia de los datos para hacerlos aptos para el análisis lineal. Se generan gráficos de los datos transformados para visualización.2. **Ajuste del modelo lineal**: Se aplica el modelo lineal a los datos transformados, tanto en bruto como normalizados. Esto se hace mediante la función `lmFit` que ajusta el modelo lineal a los datos.3. **Contrastes y ajuste bayesiano**: Se aplican los contrastes especificados en la matriz de contrastes utilizando `contrasts.fit`, y luego se realiza un ajuste bayesiano con `eBayes` para determinar la significancia estadística de las comparaciones entre los grupos experimentales.Se va a proceder inspeccionando la normalización de los datos de expresión diferencial mediante la visualización de la relación media-varianza utilizando el modelo final ajustado. :::{.panel-tabset}## Gráfica 3.3: Modelo Final - Tendencia Media-Varianza en Datos Brutos```{r}# Datos brutosplotSA(efit.raw, main="Final model: Mean−variance trend")title(sub="Datos brutos")```## Gráfica 3.4: Modelo Final - Tendencia Media-Varianza en Datos Filtrados y Normalizados```{r}# Datos normalizadosplotSA(efit.norm, main="Final model: Mean−variance trend")title(sub="Datos filtrados y normalizados")```:::En las Gráficas 3.3 y 3.4, se compara la tendencia media-varianza para los datos en bruto y los datos filtrados y normalizados, respectivamente. La Gráfica 3.3 muestra una considerable dispersión en la desviación estándar en función de la expresión media logarítmica, con muchos puntos desviándose significativamente de la línea de referencia de 1.0, especialmente en los valores de expresión más bajos y más altos. Esto indica una gran variabilidad inherente en los datos originales. En contraste, la Gráfica 3.4 presenta una dispersión mucho menor y más consistente a lo largo de diferentes niveles de expresión media logarítmica, con la mayoría de los puntos más cercanos a la línea de referencia de 1.0. Esta menor variabilidad después del filtrado y la normalización sugiere que estos pasos han mejorado significativamente la calidad de los datos, haciendo que las mediciones de expresión sean más comparables y precisas para el análisis diferencial. # Test de Múltiples ComparacionesFinalmente, se utilizará este código para identificar y resumir el número de genes expresados diferencialmente en diferentes comparaciones basadas en el valor p y el cambio de pliegue logarítmico (logFC) en datos normalizados y en datos en bruto.:::{.panel-tabset}## Número de Genes Expresados de Forma Diferencial por P-Value en cada Comparación (Datos Normalizados)```{r}### Esta función muestra el número de genes que se expresa de forma diferencial por pvalue en cada comparación #### Sobre los datos normalizadosknitr::kable(summary(decideTests(efit.norm)))```## Número de Genes Expresados de Forma Diferencial por P-Value en cada Comparación (Datos Brutos)```{r}# Sobre los datos brutosknitr::kable(summary(decideTests(efit.raw)))```## Número de Cambios en Base-Log (Normalizados y Filtrados)```{r}### Otro filtro muy utilizado es las veces de cambio en base logarítmica, logFC #### lfc: logarithm of fold change; 1 significa un FC 2^1 = 2# treat() es una función alternativa a eBayes() para tener en cuenta el logFCtfit <-treat(vfit.norm, lfc=1)dt <-decideTests(tfit)knitr::kable(summary(dt))```## Número de Cambios en Base-Log (Brutos)```{r}# Veamos lo mismo con los datos sin filtrar ni normalizartfit.raw <-treat(vfit.raw, lfc=1)dt.raw <-decideTests(tfit.raw)knitr::kable(summary(dt.raw))```:::En este código, se realizan las siguientes acciones:1. **Identificación de genes expresados diferencialmente por valor p**: - **Datos normalizados**: Se utiliza la función `decideTests` sobre el objeto `efit.norm` para identificar los genes que se expresan de forma diferencial en las comparaciones especificadas en la matriz de diseño. El resumen de estos resultados se muestra con `summary`. - **Datos brutos**: Se realiza el mismo procedimiento sobre los datos en bruto utilizando el objeto `efit.raw`.2. **Filtrado por cambio de pliegue logarítmico (logFC)**: - **Datos normalizados**: Se utiliza la función `treat` en lugar de `eBayes` para tener en cuenta el logFC. Un logFC de 1 significa un cambio de pliegue de 2^1 = 2. El objeto resultante `tfit` se pasa a `decideTests` para identificar los genes diferencialmente expresados, y se muestra un resumen de estos resultados. - **Datos brutos**: Se repite el mismo procedimiento para los datos en bruto utilizando el objeto `vfit.raw`.Finalmente, se va a proceder a comparar la expresión diferencial de genes entre las condiciones "BasalvsLP" y "BasalvsML", identificándose la intersección de genes diferencialmente expresados en ambas comparaciones, y se visualizan y guardan los resultados.:::{.panel-tabset}## Gráfica 4.1: Diagrama de Venn de Genes con Mayor Expresión Diferencial```{r}# Dibujamos un diagrama de Venn para representar las comparacionesvennDiagram(dt[,1:2], circle.col=c("turquoise", "salmon"))```El diagrama de Venn muestra la comparación de genes con expresión diferencial entre las condiciones "BasalvsLP" y "BasalvsML". En este diagrama, el círculo izquierdo representa los genes diferencialmente expresados en la comparación "BasalvsLP", mientras que el círculo derecho representa los genes diferencialmente expresados en la comparación "BasalvsML". Se observa que 672 genes son exclusivos de la comparación "BasalvsLP", 908 genes son exclusivos de la comparación "BasalvsML", y 2340 genes son comunes a ambas comparaciones. El número total de genes analizados es 10245. Estos resultados indican que hay una considerable superposición de genes con expresión diferencial entre las dos condiciones comparadas, lo que sugiere que existen cambios comunes en la expresión génica cuando se comparan las condiciones Basal con LP y Basal con ML. ## ¿Cuántos son?```{r}### Comparamos los genes con expresión diferencial entre las condiciones BasalvsLP y BasalvsML #### Identificación de genes expresados diferencialmente en ambas comparacionesde.common <-which(dt[,1] !=0& dt[,2] !=0)# ¿Cuántos son?length(de.common)```## ¿Cómo se llaman los 20 primeros?```{r}# ¿Cómo se llaman los 20 primeros?head(tfit$genes$SYMBOL[de.common], n=20)```:::```{r}### Escribimos los resultados ###write.fit(tfit, dt, file="all_genes_results.txt")```En este código, se realizan las siguientes acciones:1. **Identificación de genes con expresión diferencial común**: - Se determina qué genes están expresados diferencialmente en ambas comparaciones ("BasalvsLP" y "BasalvsML") utilizando la función `which` y la condición `dt[,1] != 0 & dt[,2] != 0`. Los índices de estos genes se almacenan en `de.common`.2. **Conteo y visualización de genes**: - Se cuenta el número de genes en común utilizando `length(de.common)`. - Se muestran los nombres de los primeros 20 genes comunes utilizando `head(tfit$genes$SYMBOL[de.common], n=20)`.3. **Visualización con diagrama de Venn**: - Se genera un diagrama de Venn para representar visualmente la superposición de genes expresados diferencialmente en las dos comparaciones.