¡Estimados estudiantes!
Es un placer tenerlos hoy en este taller intensivo de análisis de datos en RStudio, diseñado específicamente para las particularidades de la biometría y la bioestadística. Como su docente, mi objetivo es que salgan de aquí con las herramientas y la confianza necesarias para abordar sus propios conjuntos de datos, desde la exploración inicial hasta la generación de visualizaciones elocuentes.
En el campo de la bioestadística, la capacidad de extraer información significativa de datos complejos es fundamental. R y RStudio nos ofrecen un entorno potente y flexible para lograrlo. A lo largo de este taller, nos centraremos en tres pilares fundamentales del análisis exploratorio: el análisis univariado, el análisis bivariado y la creación de visualizaciones informativas. Utilizaremos conjuntos de datos ya disponibles en R para facilitar el seguimiento y la práctica.
Al finalizar este taller, ustedes serán capaces de:
ggplot2 para comunicar hallazgos.Antes de sumergirnos en el análisis, vamos a configurar nuestro
entorno y cargar los paquetes necesarios. Hoy trabajaremos
principalmente con tidyverse, una colección de paquetes que
incluye ggplot2 (para visualizaciones) y dplyr
(para manipulación de datos).
# Instalación de paquetes (solo si no los tienen instalados)
#install.packages("tidyverse")
#install.packages("patchwork") # Útil para combinar gráficos
# Carga de paquetes
library(tidyverse)
library(patchwork) # Para combinar gráficos
library(ggplot2)
Para este taller, utilizaremos el conjunto de datos
iris, un clásico en R que contiene medidas
de sépalos y pétalos de tres especies de flores de iris. Es un excelente
ejemplo para practicar con variables cuantitativas y cualitativas.
# Cargar el conjunto de datos iris (ya está disponible en R)
data("iris")
# Ver la estructura del conjunto de datos
str(iris)
## 'data.frame': 150 obs. of 5 variables:
## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
# Ver las primeras filas
head(iris)
# Obtener un resumen estadístico
summary(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## Species
## setosa :50
## versicolor:50
## virginica :50
##
##
##
iris? Identifiquen las variables
cuantitativas y cualitativas. ¿Qué tipo de
datos son Sepal.Length, Sepal.Width,
Petal.Length, Petal.Width? ¿Y
Species?La base de datos consta de 150 observaciones, cinco variables. Cuatro
variables numéricas continuas, que podrían utilizar unidades de medida
de longitud, las cuales son: longitud de los sépalos
(Sepal.Length), ancho de los sépalos
(Sepal.Width), longitud de los pétalos
(Petal.Length), ancho de los pétalos
(Petal.Width) y una variable categórica nominal politómica
que corresponde a la especie de la planta (Species).
El análisis univariado nos permite entender la distribución y las características de cada variable de forma individual.
Para variables cuantitativas, nos interesan medidas de tendencia central (media, mediana), dispersión (desviación estándar, rango intercuartílico) y la forma de la distribución.
Medidas de Tendencia Central y Dispersión:
# Longitud del sépalo (Sepal.Length)
mean(iris$Sepal.Length)
## [1] 5.843333
median(iris$Sepal.Length)
## [1] 5.8
sd(iris$Sepal.Length)
## [1] 0.8280661
IQR(iris$Sepal.Length) # Rango intercuartílico
## [1] 1.3
# Ancho de los sépalos (Sepal.Width)
mean(iris$Sepal.Width)
## [1] 3.057333
median(iris$Sepal.Width)
## [1] 3
sd(iris$Sepal.Width)
## [1] 0.4358663
IQR(iris$Sepal.Width) # Rango intercuartílico
## [1] 0.5
# Longitud de los pétalos (Petal.Length)
mean(iris$Petal.Length)
## [1] 3.758
median(iris$Petal.Length)
## [1] 4.35
sd(iris$Petal.Length)
## [1] 1.765298
IQR(iris$Petal.Length) # Rango intercuartílico
## [1] 3.5
# Ancho de los sépalos (Petal.Width)
mean(iris$Petal.Width)
## [1] 1.199333
median(iris$Petal.Width)
## [1] 1.3
sd(iris$Petal.Width)
## [1] 0.7622377
IQR(iris$Petal.Width) # Rango intercuartílico
## [1] 1.5Visualizaciones:
Histograma: Nos muestra la distribución de una variable continua.
ggplot(iris, aes(x = Sepal.Length)) +
geom_histogram(binwidth = 0.5, fill = "skyblue", color = "black") +
labs(title = "Histograma de la Longitud del Sépalo",
x = "Longitud del Sépalo (cm)",
y = "Frecuencia") +
theme_minimal()
Diagrama de Caja (Boxplot): Útil para visualizar la distribución, la mediana, los cuartiles y los valores atípicos.
ggplot(iris, aes(y = Sepal.Length)) +
geom_boxplot(fill = "lightgreen") +
labs(title = "Diagrama de Caja de la Longitud del Sépalo",
y = "Longitud del Sépalo (cm)") +
theme_minimal()
Discusión: ¿Qué nos dicen el histograma y el
boxplot sobre la distribución de Sepal.Length? ¿Es
simétrica? ¿Hay valores atípicos?
Para la longitud de los sépalos de las diferentes especies, se puede apreciar, que los datos representados en el histograma asimétricos hacia la derecha y en el boxplot, se observa que la línea que representa la mediana dentro de la caja no se encuentra en la mitad, así como que los bigotes no parecen de igual longitud. Todo esto podría dar cuenta de una posible distribucíón anormal de los datos.
Para variables cualitativas, nos interesan las frecuencias y las proporciones de cada categoría.
Tablas de Frecuencia:
table(iris$Species) # Frecuencias absolutas
##
## setosa versicolor virginica
## 50 50 50
prop.table(table(iris$Species)) # Frecuencias relativas
##
## setosa versicolor virginica
## 0.3333333 0.3333333 0.3333333Visualizaciones:
Gráfico de Barras: Muestra la frecuencia de cada categoría.
ggplot(iris, aes(x = Species, fill = Species)) +
geom_bar() +
labs(title = "Frecuencia de Especies de Iris",
x = "Especie",
y = "Conteo") +
theme_minimal() +
guides(fill = "none") # Quitar la leyenda si es redundante
Discusión: ¿Cómo se distribuyen las especies en
el conjunto de datos iris?
El análisis bivariado nos permite explorar la relación entre dos variables.
Gráfico de Dispersión (Scatter Plot): Ideal para visualizar la relación entre dos variables continuas. Podemos observar patrones, tendencias y la fuerza de la relación.
ggplot(iris, aes(x = Sepal.Length, y = Petal.Length)) +
geom_point(alpha = 0.6, color = "darkblue") +
labs(title = "Longitud del Sépalo vs. Longitud del Pétalo",
x = "Longitud del Sépalo (cm)",
y = "Longitud del Pétalo (cm)") +
theme_minimal()
Coeficiente de Correlación: Cuantifica la fuerza y dirección de la relación lineal.
cor(iris$Sepal.Length, iris$Petal.Length)
## [1] 0.8717538Discusión: ¿Qué tipo de relación observan entre
Sepal.Length y Petal.Length? ¿Es una relación
positiva o negativa? ¿Es fuerte?
Dado el valor del coeficiente de correlaciónes mayor a 0, entonces se afirma que hay una asociación o relación positiva entre la longitud de los sépalos y la longitud de los pétalos, con un resultado fuerte considerando que el valor se encuentra entre 0.5 y 1.
Diagrama de Caja Agrupado (Grouped Boxplot): Permite comparar la distribución de una variable cuantitativa entre diferentes categorías de una variable cualitativa.
ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) +
geom_boxplot() +
labs(title = "Distribución de la Longitud del Sépalo por Especie",
x = "Especie",
y = "Longitud del Sépalo (cm)") +
theme_minimal()
Violin Plot: Similar al boxplot, pero muestra la densidad de la distribución, dando una mejor idea de la forma.
ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) +
geom_violin() +
labs(title = "Distribución de la Longitud del Sépalo por Especie (Violin Plot)",
x = "Especie",
y = "Longitud del Sépalo (cm)") +
theme_minimal()
Discusión: ¿Hay diferencias significativas en la longitud del sépalo entre las diferentes especies de iris? ¿Qué especie tiene sépalos más largos en promedio?
Se nota que la longitud de los sépalos es menor en la especie Setosa en comparación con las otras especies, sin embargo, la especie con la mayor longitud de este atributo corresponde a la especie Virginica.
Tablas de Contingencia: Muestra la frecuencia conjunta de las categorías de dos variables cualitativas.
Para este ejemplo, vamos a crear una variable cualitativa a partir de una cuantitativa para demostrar la relación. Supongamos que queremos categorizar la longitud del sépalo en “Corto” y “Largo”.
iris_mod <- iris %>%
mutate(Sepal.Length.Category = cut(Sepal.Length,
breaks = c(0, 5.5, Inf),
labels = c("Corto", "Largo")))
table(iris_mod$Species, iris_mod$Sepal.Length.Category)
##
## Corto Largo
## setosa 47 3
## versicolor 11 39
## virginica 1 49Gráfico de Barras Apiladas o Agrupadas: Visualiza las frecuencias conjuntas.
ggplot(iris_mod, aes(x = Species, fill = Sepal.Length.Category)) +
geom_bar(position = "fill") + # position = "fill" para proporciones
labs(title = "Proporción de Longitud de Sépalo por Especie",
x = "Especie",
y = "Proporción",
fill = "Longitud Sépalo") +
theme_minimal()
Entre las tres especies Setosa, menos del 7% de las muestras poseen sépalos largos, la mayoría son de sépalo corto.Versicolor y Virginica poseen la proporción con mayor número de muestras con sépalos largos, alrededor del 75% para la primera y casi el 100% para la segunda.
ggplot2 es extremadamente potente para crear gráficos
complejos añadiendo capas y facetas.
Gráfico de Dispersión con Color por Especie:
ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, color = Species)) +
geom_point(alpha = 0.7) +
labs(title = "Longitud del Sépalo vs. Longitud del Pétalo por Especie",
x = "Longitud del Sépalo (cm)",
y = "Longitud del Pétalo (cm)",
color = "Especie") +
theme_minimal()
Facetas: Permite dividir un gráfico en múltiples paneles basados en los niveles de una o más variables.
ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, color = Species)) +
geom_point(alpha = 0.7) +
facet_wrap(~ Species) + # Crea un panel para cada especie
labs(title = "Longitud del Sépalo vs. Longitud del Pétalo (por Especie)",
x = "Longitud del Sépalo (cm)",
y = "Longitud del Pétalo (cm)") +
theme_minimal() +
guides(color = "none") # Quitar la leyenda si la faceta ya la explica
Combinando Gráficos con patchwork:
Una herramienta fantástica para organizar múltiples gráficos en una sola
figura.
p1 <- ggplot(iris, aes(x = Sepal.Length)) +
geom_histogram(binwidth = 0.5, fill = "skyblue", color = "black") +
labs(title = "Histograma Sepal.Length", x = "", y = "")
p2 <- ggplot(iris, aes(y = Sepal.Length, fill = Species)) +
geom_boxplot() +
labs(title = "Boxplot Sepal.Length por Especie", x = "", y = "")
p3 <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, color = Species)) +
geom_point(alpha = 0.7) +
labs(title = "Scatter Plot por Especie", x = "", y = "")
(p1 | p2) / p3 # Combinar gráficos
Ahora es su turno. Utilicen el conjunto de datos
mtcars (también disponible en R, contiene
datos de rendimiento de automóviles) o un conjunto de datos propio si lo
desean, para realizar los siguientes análisis y visualizaciones.
mpg (millas por
galón):
mpg.mpg.
Interpreten los resultados.Se inicia con el cargue y visualización inicial del conjunto de datos.
# Carga de datos
data("mtcars")
# Estructura del conjunto de datos
str(mtcars)
## 'data.frame': 32 obs. of 11 variables:
## $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
## $ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
## $ disp: num 160 160 108 258 360 ...
## $ hp : num 110 110 93 110 175 105 245 62 95 123 ...
## $ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
## $ wt : num 2.62 2.88 2.32 3.21 3.44 ...
## $ qsec: num 16.5 17 18.6 19.4 17 ...
## $ vs : num 0 0 1 1 0 1 0 1 1 1 ...
## $ am : num 1 1 1 0 0 0 0 0 0 0 ...
## $ gear: num 4 4 4 3 3 3 3 4 4 4 ...
## $ carb: num 4 4 1 1 2 1 4 2 2 4 ...
# Ver las primeras filas
head(mtcars)
# Obtener un resumen estadístico
summary(mtcars)
## mpg cyl disp hp
## Min. :10.40 Min. :4.000 Min. : 71.1 Min. : 52.0
## 1st Qu.:15.43 1st Qu.:4.000 1st Qu.:120.8 1st Qu.: 96.5
## Median :19.20 Median :6.000 Median :196.3 Median :123.0
## Mean :20.09 Mean :6.188 Mean :230.7 Mean :146.7
## 3rd Qu.:22.80 3rd Qu.:8.000 3rd Qu.:326.0 3rd Qu.:180.0
## Max. :33.90 Max. :8.000 Max. :472.0 Max. :335.0
## drat wt qsec vs
## Min. :2.760 Min. :1.513 Min. :14.50 Min. :0.0000
## 1st Qu.:3.080 1st Qu.:2.581 1st Qu.:16.89 1st Qu.:0.0000
## Median :3.695 Median :3.325 Median :17.71 Median :0.0000
## Mean :3.597 Mean :3.217 Mean :17.85 Mean :0.4375
## 3rd Qu.:3.920 3rd Qu.:3.610 3rd Qu.:18.90 3rd Qu.:1.0000
## Max. :4.930 Max. :5.424 Max. :22.90 Max. :1.0000
## am gear carb
## Min. :0.0000 Min. :3.000 Min. :1.000
## 1st Qu.:0.0000 1st Qu.:3.000 1st Qu.:2.000
## Median :0.0000 Median :4.000 Median :2.000
## Mean :0.4062 Mean :3.688 Mean :2.812
## 3rd Qu.:1.0000 3rd Qu.:4.000 3rd Qu.:4.000
## Max. :1.0000 Max. :5.000 Max. :8.000
La base de datos mtcars contiene 11 variables con 32 observaciones.
Nueve variables numéricas, de estas, seis son continuas: millas por
galón (mpg), desplazamiento (disp), relación
eje trasero (drat), peso (wt), tiempo de
cuarto de milla (qsec), caballos de fuerza
(hp) y tres son discretas, número de cilindros
(cyl), número de marchas (gear) y número de
carburadores (carb). Solo dos variables son categóricas y
ambas son dicotómicas: tipo de motor (vs) que puede ser en
“V” (0) o recto (1) y tipo de transmision (am) que puede
ser automática (0) o manual (1).
Se continúa el análisis descriptivo con la variable de las millas por
galón (mpg).
#Aplicar las funciones para el cáluclo de la media, mediana, desviación estándar y rango intercuatílico
mean(mtcars$mpg)
## [1] 20.09062
median(mtcars$mpg)
## [1] 19.2
sd(mtcars$mpg)
## [1] 6.026948
IQR(mtcars$mpg)
## [1] 7.375
En el resumen de los datos se obtuvo una media de 20.09 con una desviación típica de +/-6.02 mpg, podría tratarse de una “moderada” variabilidad en los datos; se obtuvo una mediana de 19.2, con el 50% de los datos uubicados en el rango de 7.37. Dada la diferencia entre la media y la mediana se sugiere que los datos presentan una distribución asimétrica.
Para representar la distrubución de los datos se utilizó un histograma y diagrama de cajas y bigotes:
Histograma:
ggplot(mtcars, aes(x = mpg)) +
geom_histogram(binwidth = 0.5, fill = "limegreen", color = "black") +
labs(title = "Histograma de millas por galón",
x = "Millas por galón",
y = "Frecuencia") +
theme_minimal()
Diagrama de Caja (Boxplot):
``` r
ggplot(mtcars, aes(y = mpg)) +
geom_boxplot(fill = "pink") +
labs(title = "Diagrama de Caja de la Longitud del Sépalo",
y = "Longitud del Sépalo (cm)") +
theme_minimal()
```
<img src="taller_MIB_files/figure-html/unnamed-chunk-3-1.png" width="864" />
Las visualizaciones permiten observar en el histograma ligera asimetría a la derecha. En el boxplot o diagrama de cajas y bigotes, la media y mediana parecieran ser iguales (por el tamaño y ubicación de la línea central de la caja o box), sin embargo los bigotes son de diferente longitud, la mayoría de los datos pueden ubicarse en el 50% superior a la mediana.
Se aplicó el test de normalidad de Shapiro - Wilk dada la muestra menor a 50, para determinar si los datos siguen o no una distribución normal. Se tomó como significativa con un p < a 0.05.
``` r
shapiro.test(mtcars$mpg)
```
```
##
## Shapiro-Wilk normality test
##
## data: mtcars$mpg
## W = 0.94756, p-value = 0.1229
```
El resultado (p = 0.122) demuestra que los datos presentan distribución normal, a pesar de hipotetizar tener distribución no normal, dada la observación del boxplot.
mpg y
wt (peso del vehículo):
mpg en el eje Y y
wt en el eje X.mpg y
wt.geom_smooth(method = "lm")). ¿Qué observan?Gráfico de Dispersión (Scatter Plot):
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point(alpha = 0.6, color = "darkblue") +
labs(title = "Peso del vehículo vs. millas por galón",
x = "Peso (kg)",
y = "Millas por galon (mpg)") +
geom_smooth(method = "lm", color = "red")+
theme_minimal()
Para la correlación de las variables continuas millas por galon y peso del vehículo se eligió, por la normalidad de los datos, el coeficiente de Pearson.
``` r
cor(mtcars$wt, mtcars$mpg, method = 'pearson')
```
```
## [1] -0.8676594
```
Las variables presentan una correlación negativa, a medida que aumenta el peso del vehículo este utilizará más combustible.
mpg por cyl
(número de cilindros):
cyl es una variable numérica, pero en este contexto,
podemos tratarla como categórica (4, 6 u 8 cilindros). Conviértanla a
factor si lo desean para una mejor visualización.mpg
agrupado por cyl.** Convertir la variable número de cilindros a variable categórica (factor):**
``` r
cyl_number <- factor (
mtcars$cyl,
ordered = TRUE) #ahora son ordinales
levels(cyl_number) #muestra los niveles
```
```
## [1] "4" "6" "8"
```
``` r
ggplot(mtcars, aes(x = cyl_number, y = mpg, fill = cyl_number)) +
geom_boxplot() +
scale_fill_manual(
values = c("#FF6B6B", "#bfc22f", "#45B7D1"), name = "Cilindros") +
labs(
title = "Distribución de millas por galón (mpg) por número de cilindros",
x = "Número de cilindros",
y = "Millas por galón (mpg)"
) +
theme_minimal()
```
<img src="taller_MIB_files/figure-html/unnamed-chunk-8-1.png" width="864" />
``` r
ggplot(mtcars, aes(x = cyl_number, y = mpg, fill = cyl_number)) +
geom_violin() +
scale_fill_manual(
values = c("#FF6B6B", "#bfc22f", "#45B7D1"), name = "Cilindros") +
labs(title = "Distribución de las millas por galón de los vehículos por número de cilindros (Violin Plot)",
x = "Número de cilindros",
y = "Millas por galón (mpg)") +
theme_minimal()
```
<img src="taller_MIB_files/figure-html/unnamed-chunk-8-2.png" width="864" />
Se describe, de acuerdo con las visualizaciones de los datos relacionados con la variable millas por galon agrupadas por número de cilindros que los vehículos de 4 cilindros hacen más uso de combustible, en relación a los vehículos de 6 y 8 cilindros, siendo estos último los de menor consumo.
hp (caballos de
fuerza) vs. qsec (tiempo en un cuarto de milla), coloreado
por am (tipo de transmisión: 0 = automática, 1 =
manual).cyl). am_f<-as.factor(mtcars$am)
ggplot(mtcars, aes(x = hp, y = qsec, color = am_f)) +
geom_point(alpha = 0.7) +
facet_wrap(~ cyl) +
labs(title = "Caballos de fuerza vs. tiempo en un cuarto de milla",
x = "Caballos de fuerza (HP)",
y = "Tiempo en un cuarto de milla (seg)") +
theme_minimal()
guides(col = "Cilindros")
## <Guides[1] ggproto object>
##
## colour : "Cilindros"
Hemos cubierto los fundamentos del análisis exploratorio de datos en RStudio para bioestadística. Recuerden que este es solo el punto de partida. La clave está en la práctica constante y en la curiosidad por sus datos.
El mayor desafío yace en entender el porqué de ciertas estructuras sintácticas en la programación, especialmente, al momento de la visualización de los datos.
ggplot2 les
resultaron más útiles?La creación de grupos contiguos o facetas, para la visualización de datos categóricos agrupados.
¡Excelente trabajo a todos! Espero que este taller les haya sido de gran utilidad para fortalecer sus habilidades en el análisis de datos con R. Estoy disponible para cualquier pregunta que surja a partir de ahora.
tidyverse. https://r4ds.had.co.nz/ggplot2.¡Gracias por su atención y participación! ```