La visualización de datos es la representación gráfica de información y datos mediante el uso de elementos como gráficos, mapas y diagramas. Su objetivo principal es hacer que volúmenes complejos de datos sean más accesibles y comprensibles, permitiendo identificar patrones, tendencias y anomalías de un vistazo.
Los paquetes que se van a trabajar con este modulo se muestran a continuación.
library(ggplot2)
library(tidyr)
library(dplyr)
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
Un histograma es una representación gráfica de la distribución de frecuencias de un conjunto de datos continuos (o discretos con muchos valores). Consiste en una serie de barras adyacentes (sin espacios entre ellas) donde el área de cada barra es proporcional a la frecuencia (absoluta o relativa) de los datos que caen dentro de un intervalo de clase o bin. Es una herramienta fundamental para explorar la forma, la centralidad, la dispersión y la presencia de valores atípicos o multimodalidad.
Los componentes del histograma son:
Eje horizontal
Representa la variable de interés dividida en intervalos contiguos de igual amplitud (aunque pueden ser de diferente anchura, lo común es usarlos iguales).
Los límites de cada intervalo deben cubrir todo el rango de los datos sin solaparse.
Eje vertical
Puede representar la frecuencia absoluta (número de observaciones por intervalo), la frecuencia relativa (proporción) o la densidad (frecuencia relativa dividida por la anchura del intervalo).
Cuando se usa densidad, el área total del histograma es 1.
Barras
Cada barra se dibuja sobre un intervalo de clase.
La altura de la barra es proporcional a la frecuencia (o densidad) y la anchura es la amplitud del intervalo.
No hay espacios entre barras porque la variable es continua.
Para este gráfico vamos a tomar el conjunto de datos que corresponde al periodo de almacén (vida de anaquel en días) de una película fotográfica de alta velocidad. Este conjunto de datos se muestra a continuación.
# Datos 1: Vida de película (días)
vida <- c(125, 140, 121, 141, 127, 125, 127, 147, 140, 124,
128, 150, 135, 122, 134, 132, 126, 121, 140, 143,
120, 127, 121, 121, 121, 130, 126, 124, 142, 131,
124, 131, 151, 141, 125, 141, 160, 137, 127, 127)
# Crear data frame
datos <- data.frame(vida)
El histograma se muestra a continuación:
# Histograma
ggplot(datos, aes(x = vida)) +
geom_histogram(binwidth = 5, fill = "steelblue", color = "white", alpha = 0.7) +
labs(title = "Distribución de la vida de película (días)",
x = "Vida (días)", y = "Frecuencia") +
theme_minimal()
A continuación se presenta un gráfico con mayor información:
# Calcular estadisticos
media_vida <- mean(vida)
sd_vida <- sd(vida)
# Cantidad de clases
k <- nclass.Sturges(vida)
ggplot(datos, aes(x = vida)) +
geom_histogram(
aes(y = after_stat(count)),
binwidth = k, # Numero de barras
fill = "steelblue",
color = "white",
alpha = 0.7
) +
geom_density(
aes(y = after_stat(count * 5)),
linewidth = 1.2
) +
geom_vline(
xintercept = media_vida,
color = "red",
linewidth = 1.2,
linetype = "dashed"
) +
annotate(
"text",
x = Inf,
y = Inf,
label = paste0(
"Media = ", round(media_vida, 2),
"\nDE = ", round(sd_vida, 2)
),
hjust = 1.1,
vjust = 2,
size = 5,
fontface = "bold"
) +
labs(
title = "Distribución de la vida de película (días)",
x = "Vida (días)",
y = "Frecuencia"
) +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(
size = 20,
face = "bold",
hjust = 0.5
),
axis.title = element_text(
size = 16,
face = "bold"
),
axis.text = element_text(
size = 13
)
)
Un diagrama de caja y bigotes (o boxplot) es una representación gráfica estandarizada que resume la distribución de un conjunto de datos mediante cinco estadísticos clave: mínimo, primer cuartil (\(Q1\)), mediana (\(Q2\)), tercer cuartil (\(Q3\)) y máximo. También identifica valores atípicos (outliers) que se alejan del resto de los datos. Es ampliamente utilizado para comparar distribuciones entre grupos y detectar asimetrías o dispersiones inusuales.
Los componentes del diagrama de caja y bigotes son:
Caja
El rectángulo central representa el rango intercuartílico (IQR), que es la distancia entre el primer cuartil (Q1) y el tercer cuartil (Q3):
\[IQR = Q_3 - Q_1\]
Dentro de la caja se dibuja una línea que indica la mediana (Q2).
La altura de la caja refleja la dispersión del 50% central de los datos.
Bigotes (whiskers)
Se extienden desde los bordes de la caja hasta los valores no atípicos más extremos, pero sin superar 1.5 veces el IQR desde Q1 o Q3.
\[ \text{Límite inferior} = Q_1 - 1.5 \times IQR \]
\[ \text{Límite superior} = Q_3 + 1.5 \times IQR \]
El bigote inferior llega hasta el valor mínimo que sea mayor o igual al límite inferior.
El bigote superior llega hasta el valor máximo que sea menor o igual al límite superior.
Valores atípicos (outliers)
Cualquier observación que quede por debajo del límite inferior o por encima del límite superior se representa con un punto (u otro símbolo) fuera de los bigotes.
Si la distancia es mayor a \(3 \times IQR\), algunos autores los llaman outliers extremos y los marcan con otro símbolo (por ejemplo, un asterisco).
Mínimo y máximo (no atípicos)
Los datos de la siguiente Tabla corresponden a las temperaturas registradas en cinco silos (A, B, C, D, E) durante cinco días (Lunes a Viernes). Cada valor es la temperatura en grados Celsius en una hora crítica.
| Silo | Lunes | Martes | Miércoles | Jueves | Viernes |
|---|---|---|---|---|---|
| A | 4.0 | 4.0 | 5.0 | 0.5 | 3.0 |
| B | 5.0 | 6.0 | 2.0 | 4.0 | 4.0 |
| C | 4.5 | 4.0 | 3.5 | 2.0 | 3.0 |
| D | 2.5 | 4.0 | 6.5 | 4.5 | 4.0 |
| E | 4.0 | 4.0 | 3.5 | 2.0 | 4.0 |
Obtenga un diagrama de caja y bigotes de los datos por silo y por día. A continuación se muestran los datos capturados en R.
# Crear data frame en formato ancho
datos_ancho <- data.frame(
Silo = c("A", "B", "C", "D", "E"),
Lunes = c(4.0, 5.0, 4.5, 2.5, 4.0),
Martes = c(4.0, 6.0, 4.0, 4.0, 4.0),
Miercoles = c(5.0, 2.0, 3.5, 6.5, 3.5),
Jueves = c(0.5, 4.0, 2.0, 4.5, 2.0),
Viernes = c(3.0, 4.0, 3.0, 4.0, 4.0)
)
# Transformar a formato largo (una fila por observación)
datos_largo <- pivot_longer(datos_ancho,
cols = Lunes:Viernes,
names_to = "Dia",
values_to = "Temperatura")
# Mostrar primeras filas
head(datos_largo)
## # A tibble: 6 × 3
## Silo Dia Temperatura
## <chr> <chr> <dbl>
## 1 A Lunes 4
## 2 A Martes 4
## 3 A Miercoles 5
## 4 A Jueves 0.5
## 5 A Viernes 3
## 6 B Lunes 5
El siguiente gráfico muestra la distribución de temperaturas observadas en cada silo durante los cinco días. Permite comparar la mediana, la dispersión y la presencia de valores atípicos.
ggplot(datos_largo, aes(x = Silo, y = Temperatura, fill = Silo)) +
geom_boxplot(alpha = 0.7, outlier.color = "red", outlier.size = 2) +
labs(title = "Distribución de temperaturas por silo",
x = "Silo", y = "Temperatura (°C)") +
theme_minimal() +
theme(legend.position = "none")
Una manera más elegante de mostrar el gráfico y que contenga más información se muestra a continuación.
# Calcular media y desviación estándar por silo
estadisticas <- datos_largo %>%
group_by(Silo) %>%
summarise(
media = mean(Temperatura, na.rm = TRUE),
sd = sd(Temperatura, na.rm = TRUE),
ymax = max(Temperatura, na.rm = TRUE)
)
ggplot(datos_largo, aes(x = Silo, y = Temperatura, fill = Silo)) +
# Boxplot
geom_boxplot(
alpha = 0.7,
outlier.color = "red",
outlier.size = 2
) +
# Media como punto negro
stat_summary(
fun = mean,
geom = "point",
shape = 18,
size = 4,
color = "black"
) +
# Texto con media y desviación estándar
geom_text(
data = estadisticas,
aes(
x = Silo,
y = ymax + 0.5,
label = paste0(
"Media = ", round(media, 2),
"\nDE = ", round(sd, 2)
)
),
inherit.aes = FALSE,
size = 4,
fontface = "bold"
) +
labs(
title = "Distribución de temperaturas por silo",
x = "Silo",
y = "Temperatura (°C)"
) +
theme_minimal() +
theme(
legend.position = "none",
# Título principal
plot.title = element_text(
size = 18,
face = "bold",
hjust = 0.5
),
# Títulos de los ejes
axis.title.x = element_text(
size = 14,
face = "bold"
),
axis.title.y = element_text(
size = 14,
face = "bold"
),
# Etiquetas de los ejes (ticks)
axis.text.x = element_text(
size = 12,
face = "bold"
),
axis.text.y = element_text(
size = 12
)
)
Un gráfico de barras (o diagrama de barras) es una representación gráfica de datos categóricos (o discretos) donde cada categoría se representa mediante una barra rectangular cuya altura (o longitud, en barras horizontales) es proporcional a la frecuencia, porcentaje, media u otra medida resumen asociada a esa categoría. Es una herramienta fundamental en estadística descriptiva para comparar magnitudes entre grupos distintos sin implicar orden numérico continuo.
Los componentes principales son:
Eje categórico
Normalmente el eje horizontal (X) contiene las categorías (nominales u ordinales).
Cada categoría debe ser mutuamente excluyente.
Eje numérico
Normalmente el eje vertical (Y) representa la frecuencia absoluta, frecuencia relativa, porcentaje, media, suma, etc.
La escala debe comenzar en cero (salvo en casos muy justificados, porque de otro modo se exageran las diferencias).
Barras
Rectángulos separados por un espacio para indicar que las categorías son discretas (no hay continuidad).
La altura (o anchura, en barras horizontales) es proporcional al valor numérico.
Pueden tener colores o patrones para distinguir categorías o subgrupos.
Título y etiquetas
Para este ejemplo se toman los datos utilizados en el boxplot. El registro de los datos requiere una variable del tipo factor como se muestra a continuación en la creación del data frame.
# Datos
Dia <- rep(c("Lunes", "Martes", "Miércoles", "Jueves", "Viernes"), each = 4)
Silo <- rep(c("Silo 1", "Silo 2", "Silo 3", "Silo 4"), times = 5)
Temperatura <- c(4.1, 3.9, 4.2, 3.8, 4.5, 4.3, 4.6, 4.2, 4.0, 4.2, 4.1, 4.1, 2.5, 2.8,
2.7, 2.4, 3.5, 3.7, 3.8, 3.4)
# Colocar datos en data frame
datos <- data.frame(Dia, Silo, Temperatura)
# Preparar datos para grafico de barras
df_barras <- datos %>%
group_by(Dia) %>%
summarise(
Media = mean(Temperatura),
SD = sd(Temperatura),
n = n(),
SE = SD / sqrt(n),
.groups = "drop"
)
# Media global
media_global <- mean(datos$Temperatura)
La creación del gráfico de barras se muestra a continuación
ggplot(df_barras, aes(x = Dia, y = Media, fill = Dia)) +
geom_bar(stat = "identity", width = 0.7, show.legend = FALSE) +
scale_fill_brewer(palette = "Set2") +
labs(title = "Temperatura media diaria en todos los silos",
x = "Día", y = "Temperatura media (°C)") +
theme_minimal()
A continuación se presenta un gráfico con mayor información:
ggplot(df_barras,
aes(x = Dia,
y = Media,
fill = Dia)) +
geom_col(
width = 0.7,
color = "black",
linewidth = 0.5,
show.legend = FALSE
) +
# Barras de error (±1 desviación estándar)
geom_errorbar(
aes(
ymin = Media - SD,
ymax = Media + SD
),
width = 0.15,
linewidth = 0.8
) +
# Etiquetas de las medias
geom_text(
aes(label = round(Media, 2)),
vjust = -1.0,
size = 5,
fontface = "bold"
) +
# Línea de media global
geom_hline(
yintercept = media_global,
color = "red",
linewidth = 1.2,
linetype = "dashed"
) +
annotate(
"text",
x = 4.7,
y = media_global + 0.45,
label = paste(
"Media global =",
round(media_global, 2), "°C"
),
color = "red",
fontface = "bold",
size = 4.5
) +
scale_fill_brewer(palette = "Set2") +
expand_limits(
y = max(df_barras$Media + 3*df_barras$SD) + 0.5
) +
labs(
title = "Temperatura media diaria en todos los silos",
subtitle = "Las barras de error representan ±3 desviación estándar",
x = "Día",
y = "Temperatura media (°C)"
) +
theme_minimal(base_size = 14) +
theme(
legend.position = "none",
plot.title = element_text(
size = 20,
face = "bold",
hjust = 0.5
),
plot.subtitle = element_text(
size = 13,
hjust = 0.5
),
axis.title = element_text(
size = 16,
face = "bold"
),
axis.text.x = element_text(
size = 13,
face = "bold"
),
axis.text.y = element_text(
size = 13
)
)
Un diagrama de dispersión (o gráfico de dispersión) es una representación gráfica bivariada que muestra la relación entre dos variables cuantitativas. Cada observación se representa como un punto en un plano cartesiano, donde la coordenada \(x\) corresponde al valor de una variable (llamada independiente, explicativa o predictora) y la coordenada \(y\) al valor de la otra variable (dependiente, respuesta o resultado). Es una herramienta fundamental en el análisis exploratorio de datos para detectar patrones, tendencias, agrupamientos, correlaciones y valores atípicos.
Los componentes del diagrama de dispersión son:
Eje horizontal (eje X)
Representa los valores de la primera variable (normalmente la que se considera causa o predictor).
La escala debe ser continua y cubrir el rango completo de los datos.
Eje vertical (eje Y)
Representa los valores de la segunda variable (normalmente el efecto o respuesta).
También debe tener una escala continua y adecuada.
Puntos (marcas)
Cada punto \((x_{i},y_{i})\) corresponde a una observación o unidad muestral.
Se pueden usar diferentes formas, colores o tamaños para representar información adicional (una tercera variable categórica o continua).
Título y etiquetas
Línea de tendencia (opcional)
En un laboratorio se quiere investigar la forma en que se relaciona la cantidad de fibra (madera) en la pulpa con la resistencia del papel. Se obtuvieron un conjunto de datos que se muestran a continuación.
# Crear data frame
datos <- data.frame(
Porcentaje_fibra = c(4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30),
Resistencia = c(134, 145, 142, 149, 144, 160, 156, 157, 168, 166, 167, 171, 174, 183)
)
El gráfico de dispersión para este conjunto de datos se grafica con R de la siguiente forma:
# Gráfico de dispersión
ggplot(datos, aes(x = Porcentaje_fibra, y = Resistencia)) +
geom_point(alpha = 0.7, size = 3, color = "steelblue") + # puntos semitransparentes
labs(title = "Relación entre porcentaje de fibra y resistencia",
x = "Porcentaje de fibra (%)", y = "Resistencia") +
theme_minimal() +
theme(legend.position = "none") # opcional, igual que en el ejemplo
A continuación se muestra un gráfico con mayor información.
# Modelo lineal
modelo <- lm(Resistencia ~ Porcentaje_fibra, data = datos)
# Coeficientes
intercepto <- coef(modelo)[1]
pendiente <- coef(modelo)[2]
# R²
R2 <- summary(modelo)$r.squared
# Correlación
correlacion <- cor(
datos$Porcentaje_fibra,
datos$Resistencia
)
ggplot(datos,
aes(x = Porcentaje_fibra,
y = Resistencia)) +
# Puntos
geom_point(
size = 4,
color = "steelblue",
alpha = 0.8
) +
# Línea de regresión
geom_smooth(
method = "lm",
se = TRUE,
color = "red",
linewidth = 1.2
) +
# Etiquetas de cada observación
geom_text(
aes(label = Resistencia),
vjust = -1,
size = 3.5
) +
scale_y_continuous(
limits = c(120,200),
breaks = seq(120, 200, by = 20)
) +
# Ecuación y correlación
annotate(
"text",
x = 6,
y = max(datos$Resistencia),
hjust = 0,
size = 5,
fontface = "bold",
label = paste0(
"y = ",
round(intercepto, 2),
" + ",
round(pendiente, 2),
"x",
"\nR² = ",
round(R2, 4),
"\nr = ",
round(correlacion, 4)
)
) +
labs(
title = "Relación entre porcentaje de fibra y resistencia",
subtitle = "Ajuste mediante regresión lineal simple",
x = "Porcentaje de fibra (%)",
y = "Resistencia"
) +
theme_minimal() +
theme(
plot.title = element_text(
size = 20,
face = "bold",
hjust = 0.5
),
plot.subtitle = element_text(
size = 14,
hjust = 0.5
),
axis.title = element_text(
size = 16,
face = "bold"
),
axis.text = element_text(
size = 13
)
)
## `geom_smooth()` using formula = 'y ~ x'
Un gráfico de líneas es una representación gráfica que muestra la evolución o tendencia de una o más variables numéricas a lo largo de una variable de orden (generalmente tiempo, pero también cualquier secuencia ordenada: distancia, orden de observación, etc.). Consiste en una serie de puntos (observaciones) conectados por segmentos de línea recta. Es especialmente útil para visualizar tendencias, cambios, ciclos y velocidades de cambio en datos secuenciales.
Los componentes esenciales del gráfico de líneas son:
Eje horizontal (eje X)
Variable de orden: tiempo (años, meses, días), posición, número de observación, etc.
Debe tener un orden natural (creciente). No es adecuado para variables nominales sin orden.
Eje vertical (eje Y)
Puntos (marcas)
Representan el valor observado \((x_{i},y_{i})\) en cada posición \(x_{i}\).
A veces se omiten cuando hay muchos puntos y se prefiere solo la línea.
Líneas
Segmentos que conectan puntos consecutivos en el orden de X.
La conexión implica continuidad entre observaciones (se asume que entre dos puntos la variable evoluciona de manera suave).
Múltiples líneas
Se pueden añadir varias líneas para comparar diferentes series (p. ej., temperaturas de distintos silos a lo largo del tiempo).
Cada línea debe tener un color o estilo diferente con su respectiva leyenda.
Título, etiquetas de ejes y leyenda
Una empresa quiere ver cómo evolucionan las horas extra a lo lago de varias semanas. Para ello recopila información de recursos humanos y se obtienen los siguientes datos.
# Crear data frame
datos <- data.frame(
Semana = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22),
Horas_extra = c(340, 95, 210, 809, 80, 438, 107, 180, 100, 550, 220, 50, 193, 290, 340, 115, 362, 300, 75, 93, 320, 154)
)
Con este conjunto de datos se procede a realizar el gráfico de líneas que se muestra a continuación.
# Gráfico de líneas
ggplot(datos, aes(x = Semana, y = Horas_extra)) +
geom_line(color = "steelblue", linewidth = 1) + # línea principal
geom_point(color = "steelblue", size = 2, alpha = 0.7) + # puntos para resaltar valores
labs(title = "Evolución de horas extra por semana",
x = "Semana", y = "Horas extra") +
theme_minimal() +
theme(legend.position = "none")
A continuación se presenta un gráfico con mayor información:
media_horas <- mean(datos$Horas_extra)
sd_horas <- sd(datos$Horas_extra)
semana_max <- datos$Semana[which.max(datos$Horas_extra)]
valor_max <- max(datos$Horas_extra)
semana_min <- datos$Semana[which.min(datos$Horas_extra)]
valor_min <- min(datos$Horas_extra)
ggplot(datos,
aes(x = Semana,
y = Horas_extra)) +
# Línea principal
geom_line(
color = "steelblue",
linewidth = 1.2
) +
# Puntos
geom_point(
color = "steelblue",
size = 3.5,
alpha = 0.8
) +
# Etiquetas de valores
geom_text(
aes(label = Horas_extra),
vjust = -0.8,
size = 3.5
) +
# Línea de tendencia
geom_smooth(
method = "lm",
se = FALSE,
color = "red",
linewidth = 1.2,
linetype = "dashed"
) +
# Línea de la media
geom_hline(
yintercept = media_horas,
color = "darkgreen",
linewidth = 1,
linetype = "dotted"
) +
# Punto máximo
geom_point(
data = subset(datos, Horas_extra == valor_max),
color = "red",
size = 5
) +
# Punto mínimo
geom_point(
data = subset(datos, Horas_extra == valor_min),
color = "orange",
size = 5
) +
# Resumen estadístico
annotate(
"text",
x = 16,
y = max(datos$Horas_extra),
hjust = 0,
vjust = 1.0,
size = 4.0,
fontface = "bold",
label = paste0(
"Media = ", round(media_horas, 1),
"\nDE = ", round(sd_horas, 1),
"\nMáx = ", valor_max,
" (Sem. ", semana_max, ")",
"\nMín = ", valor_min,
" (Sem. ", semana_min, ")"
)
) +
scale_x_continuous(
breaks = 1:22
) +
scale_y_continuous(
limits = c(0,1000),
breaks = seq(0, 1000, by = 100)
) +
labs(
title = "Evolución de horas extra por semana",
subtitle = "Seguimiento semanal de horas extra trabajadas",
x = "Semana",
y = "Horas extra"
) +
theme_minimal(base_size = 14) +
theme(
plot.title = element_text(
size = 20,
face = "bold",
hjust = 0.5
),
plot.subtitle = element_text(
size = 14,
hjust = 0.5
),
axis.title = element_text(
size = 16,
face = "bold"
),
axis.text = element_text(
size = 12
),
panel.grid.minor = element_blank()
)
## `geom_smooth()` using formula = 'y ~ x'