Aplicación de Programas Informáticos 2026

Análisis Exploratorio de Datos

Author
Affiliation

Cátedra de Cálculo Estadístico y Biometría

Facultad de Ciencias Agrarias, UNCUYO

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.

#install.packages("palmerpenguins")
library(palmerpenguins)

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<-penguins
class(penguins)
[1] "tbl_df"     "tbl"        "data.frame"
str(penguins) #Compactly display the internal structure of an R objec
tibble [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 

💻 Actividad: aplicar la función summary para las otras variables cualitativas

Limpieza de datos

penguins2 <- drop_na(penguins) # del paquete {tidyr}

penguins1 <- na.omit(penguins) # de {stats}
Important

¿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

💻 Actividad: crear la tabla de frecuencias para las otras variables cualitativas

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

💻 Actividad: siguiendo el procedimiento anterior ¿cómo puedo explorar rápidamente las variables cualitativas?

# 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:

  1. Proporcionar una tabla de datos a la función ggplot. Es el primer argumento (data) y se puede utilizar el operador pipe.

  2. 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ón ggplot, y se especifica con la función aes (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) son x e y, 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ón aes.

  3. 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 funciones geom_xxx.

  4. 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 (funciones scale_*_xxx); de estadísticos, para crear nuevas variables a representar basadas en los datos (funciones stat_xxx).

  5. Añadir un tema al gráfico: por ejemplo, en blanco y negro, o con especificaciones concretas, como el posicionamiento de la leyenda.

  6. 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

💻 Actividad: crear un gráfico de barras para la variable species

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()`).

💻 Actividad: agregar otra geometria al box-plot creado

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))

💻 Actividad: crear un gráfico de dispersión para dos variables cuantitativas.

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

💻 Actividad: calcular las medidas cambianbiando el argumento type por aluguna/s de estas opciones

“full”, “common”, “robust”, “mean_sd”, “mean_se”, “median_iqr”, “median_mad”, “quantile”, “mean”, “median”, “min”, “max”