Inicio

Píldoras_R. Material de formación

[mi_blog] https://agustincastro.es

[RPubs] https://rpubs.com/acastro

[GitHub-R] https://github.com/acastromartinez/GITHUB---R

Sobre la técnica

En esta práctica trabajaremos con la técnica de Análisis de Componentes Principales (PCA, en inglés), con el fin de reducir la dimensionalidad en conjuntos de datos con un gran número de variables. PCA simplifica el análisis y mejora la visualización e interpretación de los resultados al transformar las variables originales en un nuevo conjunto de componentes principales. Estos componentes retienen la mayor cantidad de información posible utilizando menos dimensiones. Así, el primer componente principal explica la mayor parte de la varianza en los datos, mientras que cada componente subsiguiente captura la mayor cantidad de varianza restante sin redundar en la información ya explicada por los componentes anteriores.

El PCA es particularmente valioso para grandes conjuntos de datos, ya que permite una simplificación significativa del análisis y una visualización efectiva, sin sacrificar la información relevante.

Sobre el set de datos

Vamos a utilizar el dataset biopsy del paquete MASS, uno de los más populares y ampliamente utilizados en análisis estadístico. Fue desarrollado por el grupo de Venables y Ripley, y acompaña el libro Modern Applied Statistics with S.

El conjunto de datos biopsy contiene información para la clasificación de tumores mamarios en benignos o malignos según características obtenidas a partir de imágenes de biopsias por aspiración con aguja fina en masas mamarias. Los datos incluyen tanto características cuantitativas de las células como la clasificación final del tumor. Es un dataset pequeño y manejable que ofrece diversidad de características para aplicar múltiples técnicas de modelado y, es ideal para enseñar y experimentar con análisis de datos y machine learning. Además, está bien documentado y soportado en el paquete MASS de R.

Librerías

library(MASS)
# install.packages("MASS") si fuera necesario

library(tidyverse)
library(ggplot2)
library(corrplot) #*
library(GGally) #* 
library(factoextra) #*
library(gridExtra) #*

#* ver anexo

Cargar información del dataset

Datos obtenidos de los Hospitales de la Universidad de Wisconsin, Madison (Dr. Wolberg). Se basan en la evaluación de 699 biopsias de tumores mamarios. Cada uno de los nueve atributos V1-V9 se puntúa en una escala de 1 a 10. La clasificación en dos niveles, benigno y maligno, también es conocida.

data(biopsy)
citation("MASS") # como citar el dataset
## To cite the MASS package in publications use:
## 
##   Venables, W. N. & Ripley, B. D. (2002) Modern Applied Statistics with
##   S. Fourth Edition. Springer, New York. ISBN 0-387-95457-0
## 
## A BibTeX entry for LaTeX users is
## 
##   @Book{,
##     title = {Modern Applied Statistics with S},
##     author = {W. N. Venables and B. D. Ripley},
##     publisher = {Springer},
##     edition = {Fourth},
##     address = {New York},
##     year = {2002},
##     note = {ISBN 0-387-95457-0},
##     url = {https://www.stats.ox.ac.uk/pub/MASS4/},
##   }

Revisión y limpieza de datos

dim(biopsy) # dimensiones (dataset con 99 filas x 11 variables)
## [1] 699  11
str(biopsy) # tipos de variables (ver anexo)
## 'data.frame':    699 obs. of  11 variables:
##  $ ID   : chr  "1000025" "1002945" "1015425" "1016277" ...
##  $ V1   : int  5 5 3 6 4 8 1 2 2 4 ...
##  $ V2   : int  1 4 1 8 1 10 1 1 1 2 ...
##  $ V3   : int  1 4 1 8 1 10 1 2 1 1 ...
##  $ V4   : int  1 5 1 1 3 8 1 1 1 1 ...
##  $ V5   : int  2 7 2 3 2 7 2 2 2 2 ...
##  $ V6   : int  1 10 2 4 1 10 10 1 1 1 ...
##  $ V7   : int  3 3 3 3 3 9 3 3 1 2 ...
##  $ V8   : int  1 2 1 7 1 7 1 1 1 1 ...
##  $ V9   : int  1 1 1 1 1 1 1 1 5 1 ...
##  $ class: Factor w/ 2 levels "benign","malignant": 1 1 1 1 1 2 1 1 1 1 ...
head(biopsy)

Missing cases, NAs

Buscamos si hay datos faltantes en el dataset y vemos que tenemos 16 NAs en la variable V6. La función de grid.table no viene por defecto en R. Requiere de la instalación de la librería gridExtra.

colSums(is.na(biopsy)) # hay 16 NAs en la columna V6
##    ID    V1    V2    V3    V4    V5    V6    V7    V8    V9 class 
##     0     0     0     0     0     0    16     0     0     0     0
grid.table(biopsy[!complete.cases(biopsy),])

Eliminamos las filas que contienen los datos faltantes en la variable V6. La dimensión final de biopsy es de 683 filas x 11 columnas (vars).

biopsy <- drop_na(biopsy, V6) # elimino los NAs
sum(is.na(biopsy$V6)) # otra forma de comprobar
## [1] 0
dim(biopsy) 
## [1] 683  11

IDs duplicados

Existen muestras con IDs duplicados, pero con diferentes valores medidos para las distintas variables. No eliminamos por tanto ninguno de estos IDs duplicados, al contener diferente información.

# vemos si existen muestras ID duplicadas en el dataset
sum(duplicated(biopsy$ID)) # hay 53 ID duplicados
## [1] 53
biopsy$ID[duplicated(biopsy$ID)] # estos son los ID duplicados
##  [1] "1033078" "1070935" "1143978" "1171710" "1173347" "1174057" "1212422"
##  [8] "1218860" "1017023" "1100524" "1116116" "1168736" "1182404" "1182404"
## [15] "1198641" "1182404" "1198641" "320675"  "704097"  "493452"  "560680" 
## [22] "1114570" "1158247" "1276091" "1276091" "1276091" "1293439" "734111" 
## [29] "1182404" "1276091" "1105524" "1115293" "1182404" "1320077" "769612" 
## [36] "798429"  "1116192" "1240603" "1299924" "1321942" "385103"  "411453" 
## [43] "822829"  "1061990" "1238777" "1277792" "1299596" "1339781" "1354840"
## [50] "466906"  "654546"  "695091"  "897471"
duplicated <- biopsy$ID[duplicated(biopsy$ID)]
table(duplicated) # número de veces que se repite cada ID
## duplicated
## 1017023 1033078 1061990 1070935 1100524 1105524 1114570 1115293 1116116 1116192 
##       1       1       1       1       1       1       1       1       1       1 
## 1143978 1158247 1168736 1171710 1173347 1174057 1182404 1198641 1212422 1218860 
##       1       1       1       1       1       1       5       2       1       1 
## 1238777 1240603 1276091 1277792 1293439 1299596 1299924 1320077 1321942 1339781 
##       1       1       4       1       1       1       1       1       1       1 
## 1354840  320675  385103  411453  466906  493452  560680  654546  695091  704097 
##       1       1       1       1       1       1       1       1       1       1 
##  734111  769612  798429  822829  897471 
##       1       1       1       1       1
# observamos los valores de las variables para las diferentes muestras con IDs duplicadas
# son diferentes, por lo que no eliminamos duplicados. 
biopsy_duplicates <- biopsy %>%
  filter(ID %in% ID[duplicated(ID)]) %>% 
  arrange(ID)
head(biopsy_duplicates)

Benigno vs Maligno

Número de casos en el dataset para cada uno de los niveles del factor “class”. Las masas tumorales son clasificadas en uno u otro grupo.

table(biopsy$class)
## 
##    benign malignant 
##       444       239

Correlación entre variables

Para estudiar la correlación entre las variables utilizadas para realizar la clasificación de los tumores tenemos que crear una matriz de correlación. Para ello, creamos un subset a partir de biopsy que contenga exclusivamente los datos de las variables que nos interesan (V1 a V9), eliminando la columna ID. Daremos a este nuevo dataframe el nombre de biopsy_vars, dado que solo contiene las variables mencionadas.

biopsy_vars <- biopsy[, -c(1, 11)]
str(biopsy_vars)
## 'data.frame':    683 obs. of  9 variables:
##  $ V1: int  5 5 3 6 4 8 1 2 2 4 ...
##  $ V2: int  1 4 1 8 1 10 1 1 1 2 ...
##  $ V3: int  1 4 1 8 1 10 1 2 1 1 ...
##  $ V4: int  1 5 1 1 3 8 1 1 1 1 ...
##  $ V5: int  2 7 2 3 2 7 2 2 2 2 ...
##  $ V6: int  1 10 2 4 1 10 10 1 1 1 ...
##  $ V7: int  3 3 3 3 3 9 3 3 1 2 ...
##  $ V8: int  1 2 1 7 1 7 1 1 1 1 ...
##  $ V9: int  1 1 1 1 1 1 1 1 5 1 ...

Ahora creamos la matriz de correlación con la función cor de R. La guardaremos en biopsy_vars_cor.

biopsy_vars_cor <- cor(biopsy_vars)
print(biopsy_vars_cor)
##           V1        V2        V3        V4        V5        V6        V7
## V1 1.0000000 0.6424815 0.6534700 0.4878287 0.5235960 0.5930914 0.5537424
## V2 0.6424815 1.0000000 0.9072282 0.7069770 0.7535440 0.6917088 0.7555592
## V3 0.6534700 0.9072282 1.0000000 0.6859481 0.7224624 0.7138775 0.7353435
## V4 0.4878287 0.7069770 0.6859481 1.0000000 0.5945478 0.6706483 0.6685671
## V5 0.5235960 0.7535440 0.7224624 0.5945478 1.0000000 0.5857161 0.6181279
## V6 0.5930914 0.6917088 0.7138775 0.6706483 0.5857161 1.0000000 0.6806149
## V7 0.5537424 0.7555592 0.7353435 0.6685671 0.6181279 0.6806149 1.0000000
## V8 0.5340659 0.7193460 0.7179634 0.6031211 0.6289264 0.5842802 0.6656015
## V9 0.3509572 0.4607547 0.4412576 0.4188983 0.4805833 0.3392104 0.3460109
##           V8        V9
## V1 0.5340659 0.3509572
## V2 0.7193460 0.4607547
## V3 0.7179634 0.4412576
## V4 0.6031211 0.4188983
## V5 0.6289264 0.4805833
## V6 0.5842802 0.3392104
## V7 0.6656015 0.3460109
## V8 1.0000000 0.4337573
## V9 0.4337573 1.0000000

Creamos la matriz de significación con los p-values obtenidos en el cálculo de la matriz de correlación. Para esto, utilizamos la función de R, cor.mtest (en este caso, nivel de confianza del 0.95).

biopsy_vars_sig <- cor.mtest(biopsy_vars, conf.level = 0.95)
print(biopsy_vars_sig$p)
##              V1            V2            V3            V4            V5
## V1 0.000000e+00  8.964173e-81  2.064616e-84  4.027956e-42  2.411759e-49
## V2 8.964173e-81  0.000000e+00 2.567742e-258 1.544338e-104 3.535863e-126
## V3 2.064616e-84 2.567742e-258  0.000000e+00  4.146228e-96 3.061101e-111
## V4 4.027956e-42 1.544338e-104  4.146228e-96  0.000000e+00  1.627087e-66
## V5 2.411759e-49 3.535863e-126 3.061101e-111  1.627087e-66  0.000000e+00
## V6 4.050902e-66  2.402961e-98 1.807287e-107  2.058229e-90  3.828707e-64
## V7 3.880813e-56 3.184894e-127 3.567289e-117  1.153511e-89  3.199163e-73
## V8 1.260114e-51 7.433029e-110 3.018221e-109  6.883291e-69  1.734754e-76
## V9 3.148289e-21  3.398097e-37  6.531371e-34  2.125287e-30  9.266128e-41
##               V6            V7            V8           V9
## V1  4.050902e-66  3.880813e-56  1.260114e-51 3.148289e-21
## V2  2.402961e-98 3.184894e-127 7.433029e-110 3.398097e-37
## V3 1.807287e-107 3.567289e-117 3.018221e-109 6.531371e-34
## V4  2.058229e-90  1.153511e-89  6.883291e-69 2.125287e-30
## V5  3.828707e-64  3.199163e-73  1.734754e-76 9.266128e-41
## V6  0.000000e+00  4.391890e-94  9.158074e-64 7.473326e-20
## V7  4.391890e-94  0.000000e+00  1.312645e-88 1.214400e-20
## V8  9.158074e-64  1.312645e-88  0.000000e+00 1.053441e-32
## V9  7.473326e-20  1.214400e-20  1.053441e-32 0.000000e+00

Con la función corrplot creamos un diagrama de correlación. Aquí podemos ver que las variables más correlacionadas entre sí (r = 0.91) son V2 y V3 (uniformidad del tamaño y forma celular, respectivamente). Hay varias variables correlacionadas con r cercanos a 0.8. Todas los valores de r obtenidos en la matriz son positivos (+) y significativos con un nivel de confianza del 95%. El uso de la función corrplot requiere la instalación de la librería corrplot, dado que no viene de base en R.

[nota] El PCA ayuda a simplificar el análisis al reducir el número de variables mientras se conserva la mayor parte de la varianza o información relevante en los datos. Esto es especialmente útil cuando las variables están muy correlacionadas, ya que el PCA puede identificar componentes principales que capturan las relaciones subyacentes entre las variables y reducir la redundancia. Además, hace más sencilla la interpretación, al reducirse el número de variables individuales a tener en cuenta.

corrplot(biopsy_vars_cor,
         p.mat = biopsy_vars_sig$p, sig.level = 0.05,
         method = "color",
         order = "hclust",
         type = "upper",
         diag = FALSE,
         addCoef.col = "black",
         number.cex = 0.9)

PCA

La función prcomp de R se utiliza para realizar el Análisis de Componentes Principales (PCA). En este caso center = TRUE asegura que las variables estén centradas en torno a la media cero, eliminando el sesgo introducido por las diferentes medias de las variables y., scale = TRUE normaliza las variables para que tengan una varianza unitaria, asegurando que todas contribuyan igualmente al análisis, independientemente de sus escalas originales.

biopsy_PCA <- prcomp(biopsy_vars, center = TRUE, scale = TRUE)

Podemos utilizar prcomp sobre el dataframe inicial biopsy (donde no quitamos la variable ID de tipo char). En este caso es necesario indicar las columnas/variables que van a ser consideradas en el análisis. biopsy_PCA <- prcomp(biopsy[,-c(1,11)], center = TRUE, scale = TRUE)

Scree plot de la varianza

Un Scree Plot es un gráfico que muestra la varianza explicada por cada componente principal en el PCA. En el eje x se representan los componentes principales (ordenados de acuerdo con la cantidad de varianza que explican), y en el eje y se muestra la varianza explicada por cada componente.

En el gráfico resulta de especial importancia el “codo”, o punto de inflexión. Es donde la pendiente del gráfico cambia de manera significativa. Atendiendo a este, podemos ver qué número de componentes principales que explican una cantidad significativa de varianza. En español el gráfico se denomina “Gráfico de Codo”.

scree_plot <- fviz_screeplot(biopsy_PCA,
                             title = "Scree plot",
                             xlab = "Dimensiones",
                             ylab = "% Explicado de la varianza",
                             barfill = "lightblue",
                             ylim = c(0, 70),
                             addlabels = TRUE)
scree_plot

En el PCA, los primeros componentes capturan la mayor parte de la variabilidad en los datos. En este caso concreto, nuestro primer componente explica la mayor parte de la varianza (65.5%), mientras que el segundo lo hace en una proporción menor (8.6%). Estos dos componentes juntos explican el 74.1% de la varianza total. La gran diferencia entre el primer y segundo componente advierte que el primero es claramente más significativo para describir la estructura de los datos que analizamos. No obstante, el segundo podría resultarnos útil también a nivel informativo. Esto es algo que podremos ver posteriormente, conforme vayamos ahondando en los resultados obtenidos con el PCA.

Contribuciones de las variables

En el contexto del PCA, la contribución de las variables se refiere a cuánto aporta cada variable original a un componente principal específico. Este concepto es clave para entender cómo las variables originales se combinan para formar los componentes principales, así como para interpretar la importancia de cada variable en la representación del espacio de datos reducido.

Echando un vistazo, podríamos ir sacando algunas conclusiones.

Por orden, las variables que más aportarían son: V2 (uniformity of cell size): Uniformidad del tamaño celular.
V3 (uniformity of cell shape): Uniformidad de la forma celular.
V7 (bland chromatin): Cromatina blanda.
V5 (single epithelial cell size): Tamaño de las células epiteliales individuales.
V8 (normal nucleoli): Nucleolos normales.
V6 (bare nuclei): Presencia de núcleos desnudos.

La línea roja representa un umbral que indica el valor de contribución a partir del cual las variables se consideran significativas para el componente principal que estemos analizando.

El primer componente principal estaría estrechamente asociado con características relacionadas con la morfología y el tamaño de las células del tejido mamario.

Más aún, la relación entre la cromatina blanda (V7) y las características morfológicas de las células, incluyendo su tamaño y forma, está respaldada por la investigación científica en biología celular y cáncer. Hay datos que relacionan la cromatina blanda con el cáncer de mama debido a su influencia en la accesibilidad del ADN y la regulación de la expresión génica (en este caso, mayor actividad tramscripcional). Las alteraciones en la estructura y modificaciones epigenéticas de la cromatina pueden facilitar la activación de genes asociados con la malignidad y contribuir a la progresión del tumor.

contrib_plot_dim1 <- fviz_contrib(biopsy_PCA, 
                               choice = "var", 
                               axes = 1, 
                               fill = "lightblue")
                             
contrib_plot_dim1 +
  ggtitle("Contribución de las variables a DIM-1") + 
  ylab("Contribuciones (%)")

En el caso del segundo componente principal, tenemos el dominio claro de una única variable:

V9 (mitoses): Número de mitosis.

Este segundo componente estaría reflejando la actividad celular en lo que a multiplicación se refiere. Las muestras de tejidos con células no cancerígenas mostrarían tasas de mitosis normales, mientras que, los de tumores malignos, se mostrarían alterados, con valores de multiplicación significativamente más elevados.

contrib_plot_dim2 <- fviz_contrib(biopsy_PCA, 
                              choice = "var", 
                              axes = 2, 
                              fill = "lightblue")

contrib_plot_dim2 + 
  ggtitle("Contribución de las variables a DIM-2") + 
  ylab("Contribuciones (%)")

Variables loading

La “carga de las variables” o “variables loading” indica cómo cada variable original influye en los componentes principales. Los “loadings” muestran qué tan importante es cada variable para cada componente, ayudando a entender cómo se forman los componentes principales y qué variables son las más relevantes en la explicación de la variabilidad de los datos.

Podemos ver como las variables V2, V3 tienen una relación muy estrecha y fuerte con el PC1 (componente principal 1), mientras que V9 lo está claramente más con el PC2.

fviz_pca_var(biopsy_PCA, col.var = "contrib", repel = TRUE, axes = c(1, 2)) +
labs(title="Variables loading for PC1 and PC2", x="PC1", y="PC2")

Gráfico BIPLOT

Un biplot es un gráfico que combina la representación de las observaciones y las variables en el mismo espacio, generalmente en el contexto de un Análisis de Componentes Principales (PCA). Las observaciones se representan como puntos en el gráfico, mostrando cómo se distribuyen los datos en función de los componentes principales. Las variables se representan como flechas o vectores, indicando la dirección y la magnitud de su influencia en los componentes principales.

En este caso representamos las observaciones de la variable “class”, que en el dataframe biopsy_PCA guardaba la información sobre la clasificación del tumor (“benigno” o “maligno”). Para facilitar la visualización del resultado en el Biplot, es además posible indicar con diferentes colores las categorías de “benigno” y “maligno”.

fviz_pca_biplot(biopsy_PCA, 
                label = "var", 
                habillage = biopsy$class, 
                axes = c(1,2), 
                addEllipse = FALSE,
                col.var = "black") +
                scale_color_manual(values = c("lightblue", "red"))

Conclusiones

  • Comenzamos con un dataframe que contiene datos de 9 variables (V1 a V9) correspondientes a muestras obtenidas a partir de biopsias de tejido mamario tumoral.
  • Para cada muestra, tenemos clasificado el tumor como “benigno” o “maligno”.
  • El PCA nos permite reducir a dos factores (o componentes principales) la dimensionalidad, obteniendo con ellos casi un 80% de explicación de la varianza total (concretamente, un 74,1%).
  • El primer componente principal PC1 está estrechamente asociado con la morfología celular del tejido mamario muestreado (uniformidad en la forma y tamaño de las células).
  • El segundo componente principal PC2 está relacionado con la multiplicación celular, reflejando la diferente tasa de multiplicación celular (mitosis) entre muestras con tejidos tumorales benignos (tasa normal) y malignos (mayor tasa).

Anexo

MASS::biopsy

El dataset contiene las siguientes variables:

ID: Identificador de la muestra.
V1 (clump thickness): Grosor del grupo celular.
V2 (uniformity of cell size): Uniformidad del tamaño celular.
V3 (uniformity of cell shape): Uniformidad de la forma celular.
V4 (marginal adhesion): Adhesión marginal.
V5 (single epithelial cell size): Tamaño de las células epiteliales individuales.
V6 (bare nuclei): Presencia de núcleos desnudos.
V7 (bland chromatin): Cromatina blanda.
V8 (normal nucleoli): Nucleolos normales.
V9 (mitoses): Número de mitosis.
class: Clasificación del tumor, que puede ser “benigno” o “maligno”.

corrplot

La librería corrplot es una herramienta especializada para visualizar matrices de correlación de manera intuitiva y atractiva. Facilita la interpretación de relaciones entre variables al proporcionar una variedad de gráficos de correlación, como —Diagramas de Correlación (Muestra la matriz de correlación con colores y etiquetas que representan la fuerza y la dirección de las correlaciones entre pares de variables), — Gráficos de Mapa de Calor (Utiliza colores para visualizar la magnitud de las correlaciones, facilitando la identificación de patrones), entre otras.

GGally

La librería GGally en R es una extensión del paquete ggplot2, diseñada para simplificar la visualización y el análisis exploratorio de datos. Ofrece una serie de funciones que facilitan la creación de gráficos complejos y personalizados. Concretamente utilizaremos la función ggcorr, que crea matrices de correlación con el fin de ayudar a identificar patrones y relaciones entre variables. En otras prácticas hemos utilizado la librería corrplot para hacer las matrices de correlación.

factoextra

factoextra es una librería en R diseñada para facilitar la visualización y la interpretación de resultados de análisis multivariantes, como el Análisis de Componentes Principales (PCA) y el Análisis Factorial. Cuenta con funciones muy útiles para estas tareas. — fviz_pca_biplot (permite generar gráficos biplots con los que visualizar tanto las observaciones como las variables en el espacio de los componentes principales), —fviz_pca_var muestra cómo las variables contribuyen a los componentes principales, — fviz_pca_ind visualiza la distribución de las observaciones en el espacio reducido de los componentes principales, — fviz_eig muestra un gráfico de los valores propios para representar la proporción de varianza explicada por cada componente, entre otras.

gridExtra

gridExtra es una librería en R que extiende las capacidades de visualización del sistema gráfico grid, permitiendo combinar múltiples gráficos y tablas en una única figura de manera flexible. Proporciona funciones como grid.table(), para incluir tablas dentro de gráficos. Es especialmente útil para crear composiciones complejas de gráficos y tablas, facilitando la presentación de resultados en un solo espacio visual.