#install.packages("palmerpenguins")
library(palmerpenguins)Aplicación de Programas Informáticos 2026
Análisis Exploratorio de Datos
Introducción
El análisis exploratorio de datos, y en particular su visualización, es el primer análisis que se debe hacer sobre cualquier conjunto de datos. El análisis exploratorio de datos se realiza mediante las herramientas vistas en Estadística Descriptiva: las medidas resúmen, la presentación tabular y la representación gráfica.
Penguins dataset
El conjunto de datos de palmerpenguins (creado por la Dra. Kristen Gorman, la Dra. Allison Horst y la Dra. Alison Hill) del proyecto #TidyTuesday muestra datos relacionados con las especies de pingüinos (Adelia, Barbijo y Papúa) que viven en el archipiélago de Palmer, en la costa noroeste de la península Antártica.
El dataset se encuentra en el paquete palmerpenguins . Siempre es importante conocer nuestros datos y cómo se estructura la información por lo que adelante se presentan unos ejemplos de funciones básicas para explorar un dataset.
penguins<-penguinsclass(penguins)[1] "tbl_df" "tbl" "data.frame"
str(penguins) #Compactly display the internal structure of an R objectibble [344 × 8] (S3: tbl_df/tbl/data.frame)
$ species : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
$ island : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
$ bill_length_mm : num [1:344] 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
$ bill_depth_mm : num [1:344] 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
$ flipper_length_mm: int [1:344] 181 186 195 NA 193 190 181 195 193 190 ...
$ body_mass_g : int [1:344] 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
$ sex : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
$ year : int [1:344] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...
head(penguins) #Return the First or Last Parts of an Object # A tibble: 6 × 8
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
<fct> <fct> <dbl> <dbl> <int> <int>
1 Adelie Torgersen 39.1 18.7 181 3750
2 Adelie Torgersen 39.5 17.4 186 3800
3 Adelie Torgersen 40.3 18 195 3250
4 Adelie Torgersen NA NA NA NA
5 Adelie Torgersen 36.7 19.3 193 3450
6 Adelie Torgersen 39.3 20.6 190 3650
# ℹ 2 more variables: sex <fct>, year <int>
Tidyverse y su flujo de trabajo
Manipulación de datos con dplyr
El análisis de datos implica una gran cantidad de trabajo de mantenimiento: la depuración y el procesamiento de datos para facilitar el análisis posterior.
Utilizaremos el paquete dplyr en R para manipular eficazmente y calcular condicionalmente estadísticas de resumen sobre subconjuntos de un conjunto de datos grande que contiene muchas observaciones.
library(tidyverse)Variables Cualitativas
# summary is a generic function used to produce result summaries of the results of various model fitting functions
summary(penguins$species) Adelie Chinstrap Gentoo
152 68 124
Limpieza de datos
penguins2 <- drop_na(penguins) # del paquete {tidyr}
penguins1 <- na.omit(penguins) # de {stats}¿Qué se modificó en el nuevo conjunto de datos?
Tabla de frecuencias
penguins2 |>
count(sex, name = "Frecuencia_Absoluta") |>
mutate(
Frecuencia_Relativa = Frecuencia_Absoluta / sum(Frecuencia_Absoluta),
Porcentaje = Frecuencia_Relativa * 100
)# A tibble: 2 × 4
sex Frecuencia_Absoluta Frecuencia_Relativa Porcentaje
<fct> <int> <dbl> <dbl>
1 female 165 0.495 49.5
2 male 168 0.505 50.5
#Simple Tools for Examining and Cleaning Dirty Data
library(janitor)penguins2 |>
count(sex, name = "Frecuencia_Absoluta") |>
mutate(
Frecuencia_Relativa = Frecuencia_Absoluta / sum(Frecuencia_Absoluta),
Porcentaje = Frecuencia_Relativa * 100,
Frecuencia_Relativa = round(Frecuencia_Relativa, 3),
Porcentaje = round(Porcentaje, 2)
) |>
adorn_totals("row", fill = "-", na.rm = TRUE) sex Frecuencia_Absoluta Frecuencia_Relativa Porcentaje
female 165 0.495 49.55
male 168 0.505 50.45
Total 333 1.000 100.00
tabla<-penguins2 |>
count(species, sex) |>
pivot_wider(
names_from = sex,
values_from = n,
values_fill = 0
)# 1. Crear la tabla cruzada con el total por fila
tabla_cruzada <- penguins2 |>
count(species, sex) |>
pivot_wider(names_from = sex, values_from = n, values_fill = 0) |>
mutate(Total = rowSums(across(where(is.numeric))))
# 2. Agregar la fila de Total al final
tabla_cruzada |>
bind_rows(
summarise(
tabla_cruzada,
species = "Total",
across(where(is.numeric), sum)
)
)# A tibble: 4 × 4
species female male Total
<chr> <int> <int> <dbl>
1 Adelie 73 73 146
2 Chinstrap 34 34 68
3 Gentoo 58 61 119
4 Total 165 168 333
Variables Cuantitativas
# Frequency Distribution Tables, Histograms and Polygons
library(fdth)Elegimos una variable flipper_length_mm
dist_aleta <- fdt(penguins$flipper_length_mm,
k=5,
breaks="Sturges",
na.rm = TRUE) # calcula la distribución de frecuencias utilizando la regla Sturges
summary(dist_aleta) #nos brinda una tabla con los cálculos de la distribución de frecuencias. Class limits f rf rf(%) cf cf(%)
[170.28,182.886) 23 0.07 6.73 23 6.73
[182.886,195.492) 133 0.39 38.89 156 45.61
[195.492,208.098) 67 0.20 19.59 223 65.20
[208.098,220.704) 84 0.25 24.56 307 89.77
[220.704,233.31) 35 0.10 10.23 342 100.00
Componentes de un gráfico y su representación en R1
Existen diferentes sistemas en R para representar gráficos (los “base,” paquete graphics, y los “grid,” paquete lattice Sarkar, 2008), este capítulo se centra en el paquete ggplot2 (Wickham, 2016), que forma parte del tidyverse, por su amplio uso y popularidad.
El flujo de trabajo con ggplot2 se puede resumir en los siguientes pasos:
Proporcionar una tabla de datos a la función
ggplot. Es el primer argumento (data) y se puede utilizar el operador pipe.Proporcionar las columnas de la tabla de datos que serán representadas en el gráfico. Este será el segundo argumento (
mapping) de la funciónggplot, y se especifica con la funciónaes(aesthetics) como una lista de pares aesthetic = variable, de forma que el elemento especificado como aesthetic será “mapeado” a los valores de la variable. Esta especificación se puede hacer también en las funciones que añaden capas, que se explican a continuación. Los aesthetics más comunes (para muchos tipos de gráficos obligatorios) sonxey, es decir, las columnas que se usarán para el eje horizontal y el eje vertical respectivamente. Además, se pueden especificar columnas para el color, el tamaño, el símbolo de los puntos, el tipo de línea, el texto, y otros específicos del tipo de gráfico. Los aesthetics se pueden especificar también de forma “fija” (sin depender de ninguna variable) fuera de la funciónaes.Añadir las capas del gráfico con los geoms, es decir, los objetos geométricos que representan a cada variable. Esto se indica con el operador
+, como si se “sumasen” componentes al gráfico mediante funcionesgeom_xxx.Añadir otras capas al gráfico: por ejemplo, una capa de etiquetas del gráfico (función
labs); de ejes, para modificar los ejes y leyendas creados por defecto (funcionesscale_*_xxx); de estadísticos, para crear nuevas variables a representar basadas en los datos (funcionesstat_xxx).Añadir un tema al gráfico: por ejemplo, en blanco y negro, o con especificaciones concretas, como el posicionamiento de la leyenda.
Añadir “facetas” (facets). De esta forma se divide el gráfico en varios subgráficos basándose en los valores de una o más variables discretas (normalmente categóricas).
penguins2 %>%
ggplot() +
aes(x = body_mass_g) +
geom_histogram(bins = 7L, fill="cyan3", color="grey2") +
theme_minimal() Introducción a ggplot2 mediante esquisse
{esquisse} es un paquete de R, disponible en CRAN, para crear gráficos con {ggplot2}, esta aplicación le permite utilizar esquisse directamente en línea, sin tener que instalar el paquete. Antes de crear un gráfico, primero debe importar los datos que se utilizarán para crear un gráfico, o utilizar un conjunto de datos de demostración.
Gráficos para variables cuanlitativas
ggplot(penguins2) +
aes(x = species) +
geom_bar(fill = "#4682B4") +
theme_light() +
labs( x="Especie", y="Cantidad de individuos")Gráficos para variables cuantitativas
Box-plot múltiple para una variable cuantitativa y una variable cualitativa
penguins %>%
filter(!is.na(body_mass_g)) %>%
ggplot() +
aes(x = "", y = body_mass_g, fill = species) +
geom_boxplot() +
scale_fill_hue(direction = 1) +
labs(
x = "Especie de pingüino",
y = "Peso de cuerpo (g)",
title = "Peso de cuerpo de pingüinos según especie"
) +
theme_minimal() +
theme(legend.position = "top")penguins %>%
filter(!is.na(body_mass_g)) %>%
filter(!is.na(sex)) %>%
ggplot() +
aes(x = species, y = body_mass_g, fill = species) +
geom_boxplot() +
scale_fill_brewer(palette = "Accent", direction = 1) +
labs(
x = "Especie de pingüino",
y = "Peso de cuerpo (g)",
title = "Peso de cuerpo de pingüinos según especie",
caption = "Especie"
) +
theme_classic() +
theme(legend.position = "top") +
facet_wrap(vars(sex))ggplot(penguins) +
aes(x = species, y = body_mass_g, fill = species) +
geom_boxplot(alpha=0.5) +
scale_fill_brewer(palette = "Accent", direction = 1) +
labs(
x = "Especie de pingüino",
y = "Peso de cuerpo en gramos",
title = "Peso de cuerpo de pingüinos según especie",
) +
theme_classic() +
theme(legend.position = "top")Warning: Removed 2 rows containing non-finite outside the scale range
(`stat_boxplot()`).
penguins %>%
filter(!is.na(body_mass_g)) %>%
filter(!is.na(sex)) %>%
ggplot() +
aes(x = species, y = body_mass_g, fill = species) +
geom_boxplot() +
geom_jitter(aes(y = body_mass_g)) +
scale_fill_brewer(palette = "Accent", direction = 1) +
labs(
x = "Especie de pingüino",
y = "Peso de cuerpo en gramos",
title = "Peso de cuerpo de pingüinos según especie",
caption = "Especie"
) +
theme_classic() +
theme(legend.position = "top") +
facet_wrap(vars(sex))ggplot(palmerpenguins::penguins) +
aes(
x = body_mass_g,
y = flipper_length_mm,
colour = species,
shape = species
) +
geom_point(size = 1.55) +
scale_color_hue(direction = 1) +
labs(x = "Peso de cuerpo (g)", y = "Largo de aleta (mm)") +
theme_light()Warning: Removed 2 rows containing missing values or values outside the scale range
(`geom_point()`).
ggplot(data = penguins,
aes(x = body_mass_g,
y = flipper_length_mm)) +
geom_point(aes(color = species,
shape = species),
size = 3,
alpha = 0.8) +
scale_color_manual(values = c("darkorange","purple","cyan4")) +
labs(title = "Tamaño de cuerpo de pinguinos, Palmer Station LTER",
subtitle = "Largo de aleta y peso de cuerpo de para las especies Adelie, Chinstrap y Gentoo",
x = "Peso de cuerpo (g)",
y = "Largo de aleta (mm)",
color = "Especie",
shape = "Especie") +
theme(legend.position.inside = c(0.2, 0.7),
plot.title.position = "plot",
plot.caption = element_text(hjust = 0, face= "italic"),
plot.caption.position = "plot")Warning: Removed 2 rows containing missing values or values outside the scale range
(`geom_point()`).
Conociendo a los pingüinos 🐧
Medidas resumen para un variable cualitativa
Resumen de medidas para la longitud de pico por especie
penguins |>
group_by(species) |>
drop_na() |>
summarise(media_mm = mean(bill_length_mm),
desvio_mm= sd(bill_length_mm),
maximo_mm = max(bill_length_mm),
minimo_mm = min(bill_length_mm),
CV = desvio_mm/media_mm*100
)# A tibble: 3 × 6
species media_mm desvio_mm maximo_mm minimo_mm CV
<fct> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Adelie 38.8 2.66 46 32.1 6.86
2 Chinstrap 48.8 3.34 58 40.9 6.84
3 Gentoo 47.6 3.11 59.6 40.9 6.53
Utilizando rstatix
library(rstatix)medidas<-penguins |>
group_by(species, island) |>
get_summary_stats(bill_length_mm, type = "five_number")
medidas# A tibble: 5 × 9
species island variable n min max q1 median q3
<fct> <fct> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Adelie Biscoe bill_length_mm 44 34.5 45.6 37.7 38.7 40.7
2 Adelie Dream bill_length_mm 56 32.1 44.1 36.8 38.6 40.4
3 Adelie Torgersen bill_length_mm 51 33.5 46 36.6 38.9 41.1
4 Chinstrap Dream bill_length_mm 68 40.9 58 46.4 49.6 51.1
5 Gentoo Biscoe bill_length_mm 123 40.9 59.6 45.3 47.3 49.6
Footnotes
Texto tomado de Fundamentos de ciencia de datos con R↩︎