← Volver al inicio
Universidad Nacional de Costa Rica

Estructuras de datos complejas en R

Listas, listas nombradas y organización avanzada de información

Curso: EIY403 - Introducción al análisis de datos
Semana 11
II Semestre 2025
"Las estructuras de datos complejas nos permiten organizar, almacenar y manipular información de manera eficiente y flexible"
1 / 15
Universidad Nacional de Costa Rica

Agenda de la sesión

Fundamentos

  • Repaso: vectores, matrices y data frames
  • ¿Por qué necesitamos estructuras más complejas?
  • Diferencias entre Python y R

Listas en R

  • Definición y características
  • Creación de listas simples
  • Acceso a elementos de listas
  • Listas anidadas

Listas nombradas

  • Equivalente a diccionarios en Python
  • Sintaxis y uso práctico
  • Manipulación de elementos
  • Aplicaciones en análisis de datos

Conceptos avanzados

  • Introducción a clases en R (S3)
  • Listas como objetos estructurados
  • Casos de uso en química y otras ciencias
  • Ejercicios prácticos
2 / 15
Universidad Nacional de Costa Rica

Repaso: estructuras de datos básicas en R

Vector

Dimensión: 1D (una dimensión)

Restricción: Todos los elementos del mismo tipo

# Ejemplo temperaturas <- c(25.3, 26.1, 24.8, 25.5) nombres <- c("Ana", "Juan", "María")
Matriz

Dimensión: 2D (filas y columnas)

Restricción: Todos los elementos del mismo tipo

# Ejemplo datos <- matrix(1:6, nrow=2, ncol=3) # [,1] [,2] [,3] # [1,] 1 3 5 # [2,] 2 4 6
Data frame

Dimensión: 2D (filas y columnas)

Flexibilidad: Cada columna puede ser de tipo diferente

# Ejemplo experimentos <- data.frame( id = 1:3, temp = c(25, 30, 35), exito = c(TRUE, FALSE, TRUE) )
Lista

Dimensión: 1D pero puede contener cualquier cosa

Flexibilidad: Puede mezclar tipos y estructuras

# Ejemplo mi_lista <- list( numeros = 1:5, texto = "Hola", logicos = c(TRUE, FALSE) )

Conclusión: Las listas son la estructura más flexible en R, permitiendo combinar diferentes tipos de datos y estructuras en un solo objeto

3 / 15
Universidad Nacional de Costa Rica

¿Por qué necesitamos estructuras más complejas?

Limitaciones de estructuras simples

Problema 1: datos heterogéneos

Un experimento químico puede tener: nombre (texto), temperatura (número), resultados (vector), y condiciones (data frame)

Problema 2: organización lógica

Necesitamos agrupar información relacionada de manera que tenga sentido conceptualmente

Problema 3: análisis complejos

Los análisis estadísticos devuelven múltiples resultados (coeficientes, p-valores, gráficos, etc.)

Ejemplo del mundo real

# Información de un experimento químico: - Nombre del experimento - Fecha de realización - Condiciones (temperatura, pH, presión) - Mediciones (vector de concentraciones) - Resultados estadísticos - Gráficos generados - Observaciones del investigador # ¿Cómo almacenar todo esto junto?

Ventajas de estructuras complejas

Organización clara

  • Agrupa información relacionada
  • Jerarquía lógica de datos
  • Fácil de entender y mantener

Flexibilidad total

  • Mezcla diferentes tipos de datos
  • Anida estructuras dentro de otras
  • Adapta la estructura a tus necesidades

Eficiencia en el código

  • Menos variables sueltas
  • Código más limpio y legible
  • Fácil de pasar como argumento a funciones

Analogía: Piensa en una lista como un archivador donde cada cajón puede contener diferentes tipos de documentos, carpetas, o incluso otros archivadores más pequeños

4 / 15
Universidad Nacional de Costa Rica

De Python a R: equivalencias importantes

Diccionarios en Python
# Python experimento = { "nombre": "Síntesis A", "temperatura": 25.5, "pH": 7.2, "resultados": [1.2, 1.5, 1.3] } # Acceso print(experimento["temperatura"]) # 25.5
Listas nombradas en R
# R experimento <- list( nombre = "Síntesis A", temperatura = 25.5, pH = 7.2, resultados = c(1.2, 1.5, 1.3) ) # Acceso experimento$temperatura # [1] 25.5
Clases en Python
# Python class Experimento: def __init__(self, nombre, temp): self.nombre = nombre self.temperatura = temp def resumen(self): return f"{self.nombre}: {self.temperatura}°C" exp = Experimento("Test", 25) print(exp.resumen())
Listas con clase S3 en R
# R (simplificado) crear_experimento <- function(nombre, temp) { obj <- list( nombre = nombre, temperatura = temp ) class(obj) <- "Experimento" return(obj) } exp <- crear_experimento("Test", 25) class(exp) # [1] "Experimento"

Conclusión clave: En R, las listas nombradas son el equivalente más directo y práctico a los diccionarios de Python. Las clases existen pero son más avanzadas y no siempre necesarias

5 / 15
Universidad Nacional de Costa Rica

Listas en R: conceptos fundamentales

Definición

Una lista es una estructura de datos que puede contener elementos de diferentes tipos y estructuras. Es como un contenedor flexible que puede almacenar cualquier cosa.

Creación de listas simples

# Lista simple mi_lista <- list(42, "texto", TRUE, 3.14) # Ver la estructura str(mi_lista) # List of 4 # $ : num 42 # $ : chr "texto" # $ : logi TRUE # $ : num 3.14 # Ver contenido mi_lista # [[1]] # [1] 42 # # [[2]] # [1] "texto" # # [[3]] # [1] TRUE # # [[4]] # [1] 3.14

Lista con vectores

# Lista conteniendo vectores datos_lab <- list( c(25.1, 25.3, 24.9), # temperaturas c(7.2, 7.1, 7.3), # pH c("A", "B", "A") # catalizador ) # Acceder al primer elemento (vector de temperaturas) datos_lab[[1]] # [1] 25.1 25.3 24.9

Acceso a elementos

Tres formas de acceder:

mi_lista <- list(10, 20, 30) # 1. Con [[ ]] - devuelve el elemento mi_lista[[1]] # [1] 10 # 2. Con [ ] - devuelve una sublista mi_lista[1] # [[1]] # [1] 10 # 3. Por posición múltiple mi_lista[c(1, 3)] # [[1]] # [1] 10 # # [[2]] # [1] 30

Diferencia importante:

  • [[1]] → extrae el elemento directamente
  • [1] → extrae una sublista con ese elemento

Listas anidadas

# Lista dentro de otra lista experimentos <- list( exp1 = list(temp = 25, pH = 7.0), exp2 = list(temp = 30, pH = 6.5) ) # Acceso anidado experimentos[[1]][[1]] # 25 experimentos[[2]][[2]] # 6.5
6 / 15
Universidad Nacional de Costa Rica

Listas nombradas: el equivalente a diccionarios

¿Qué son?

Las listas nombradas son listas donde cada elemento tiene un nombre asociado. Esto hace el código más legible y es el equivalente directo a los diccionarios en Python.

Creación

# Sintaxis 1: al crear la lista experimento <- list( nombre = "Síntesis de aspirina", fecha = "2025-10-08", temperatura = 25.5, pH = 7.2, concentraciones = c(0.1, 0.2, 0.15) ) # Sintaxis 2: asignar nombres después valores <- list(100, 200, 300) names(valores) <- c("minimo", "medio", "maximo") # Ver nombres names(experimento) # [1] "nombre" "fecha" # [3] "temperatura" "pH" # [5] "concentraciones"

Ventajas

  • Legibilidad: nombres descriptivos vs. posiciones numéricas
  • Mantenimiento: fácil agregar/quitar elementos
  • Autoexplicativo: el código se documenta solo

Acceso a elementos nombrados

# Tres formas de acceder por nombre: # 1. Con $ (más común y limpio) experimento$temperatura # [1] 25.5 # 2. Con [["nombre"]] experimento[["pH"]] # [1] 7.2 # 3. Con ["nombre"] (devuelve sublista) experimento["nombre"] # $nombre # [1] "Síntesis de aspirina"

Modificación

# Cambiar un valor existente experimento$temperatura <- 30.0 # Agregar un nuevo elemento experimento$presion <- 1.2 # Eliminar un elemento experimento$presion <- NULL # Ver estructura actualizada str(experimento)

Caso práctico

# Información de un estudiante estudiante <- list( carnet = "B12345", nombre = "María López", carrera = "Química Industrial", notas = c(85, 90, 88, 92), aprobado = TRUE ) # Calcular promedio promedio <- mean(estudiante$notas) cat("Promedio de", estudiante$nombre, ":", promedio) # Promedio de María López : 88.75
7 / 15
Universidad Nacional de Costa Rica

Manipulación avanzada de listas

Operaciones comunes

# Crear lista de ejemplo datos <- list( a = 1:5, b = 10:15, c = c("x", "y", "z") ) # Longitud de la lista length(datos) # 3 # Nombres de elementos names(datos) # "a" "b" "c" # Verificar si existe un nombre "a" %in% names(datos) # TRUE # Combinar listas nueva_lista <- c(datos, list(d = 100)) length(nueva_lista) # 4

Iterar sobre listas

# Con for loop for (i in 1:length(datos)) { cat("Elemento", i, ":", datos[[i]], "\n") } # Con lapply (retorna lista) lapply(datos, length) # $a # [1] 5 # $b # [1] 6 # $c # [1] 3 # Con sapply (retorna vector) sapply(datos, length) # a b c # 5 6 3

Filtrar elementos

# Solo elementos numéricos numeros <- datos[sapply(datos, is.numeric)] # Solo vectores de longitud > 3 largos <- datos[sapply(datos, function(x) length(x) > 3)]

Conversión entre estructuras

# Lista a data frame (si es posible) mi_lista <- list( nombre = c("Ana", "Juan", "María"), edad = c(25, 30, 28), ciudad = c("San José", "Heredia", "Alajuela") ) df <- as.data.frame(mi_lista) df # nombre edad ciudad # 1 Ana 25 San José # 2 Juan 30 Heredia # 3 María 28 Alajuela # Data frame a lista (por columnas) lista_cols <- as.list(df) # Data frame a lista (por filas) lista_filas <- split(df, 1:nrow(df))

Búsqueda en listas

experimentos <- list( exp1 = list(temp = 25, resultado = "exitoso"), exp2 = list(temp = 30, resultado = "fallido"), exp3 = list(temp = 25, resultado = "exitoso") ) # Encontrar experimentos exitosos exitosos <- experimentos[ sapply(experimentos, function(x) x$resultado == "exitoso") ] length(exitosos) # 2

Funciones útiles

  • unlist() - convierte lista a vector
  • str() - muestra estructura completa
  • lengths() - longitud de cada elemento
  • rapply() - aplica función recursivamente
8 / 15
Universidad Nacional de Costa Rica

Aplicación práctica: experimentos químicos

Caso 1: registro de experimento individual

# Crear registro completo de un experimento experimento_sintesis <- list( metadata = list( nombre = "Síntesis de ácido acetilsalicílico", fecha = "2025-10-08", investigador = "Dr. Ramírez", laboratorio = "Lab A" ), condiciones_iniciales = list( temperatura = 25.5, presion = 1.0, pH = 7.0, humedad = 65 ), reactivos = data.frame( nombre = c("Ácido salicílico", "Anhídrido acético"), cantidad = c(2.0, 3.0), unidad = c("g", "mL") ), mediciones = list( tiempo = c(0, 10, 20, 30, 40, 50), # minutos temperatura = c(25, 60, 75, 75, 70, 65), pH = c(7.0, 6.5, 6.2, 6.0, 6.1, 6.2) ), resultados = list( rendimiento = 85.3, # porcentaje pureza = 96.7, # porcentaje aspecto = "cristales blancos", solubilidad = "alta en etanol" ), observaciones = "Reacción exotérmica. Cristalización exitosa." ) # Acceso fácil a información específica experimento_sintesis$metadata$nombre experimento_sintesis$resultados$rendimiento experimento_sintesis$mediciones$temperatura

Ventajas de esta organización

Organización lógica

  • Toda la información del experimento en un solo objeto
  • Estructura jerárquica clara y comprensible
  • Fácil de expandir con nueva información

Análisis simplificado

# Calcular temperatura promedio mean(experimento_sintesis$mediciones$temperatura) # [1] 61.66667 # Crear gráfico de temperatura vs tiempo plot( experimento_sintesis$mediciones$tiempo, experimento_sintesis$mediciones$temperatura, type = "b", main = experimento_sintesis$metadata$nombre, xlab = "Tiempo (min)", ylab = "Temperatura (°C)" )

Reutilización

# Función para crear resumen resumen_experimento <- function(exp) { cat("=== RESUMEN DEL EXPERIMENTO ===\n") cat("Nombre:", exp$metadata$nombre, "\n") cat("Fecha:", exp$metadata$fecha, "\n") cat("Rendimiento:", exp$resultados$rendimiento, "%\n") cat("Pureza:", exp$resultados$pureza, "%\n") cat("Temp. promedio:", mean(exp$mediciones$temperatura), "°C\n") } resumen_experimento(experimento_sintesis)
9 / 15
Universidad Nacional de Costa Rica

Caso 2: gestión de múltiples experimentos

Base de datos de experimentos

# Lista de múltiples experimentos base_experimentos <- list( EXP001 = list( nombre = "Síntesis A", fecha = "2025-10-01", temperatura = 25, pH = 7.0, rendimiento = 85.3, exitoso = TRUE ), EXP002 = list( nombre = "Síntesis B", fecha = "2025-10-03", temperatura = 30, pH = 6.5, rendimiento = 78.2, exitoso = TRUE ), EXP003 = list( nombre = "Síntesis C", fecha = "2025-10-05", temperatura = 35, pH = 6.0, rendimiento = 45.1, exitoso = FALSE ) ) # Ver todos los experimentos names(base_experimentos) # [1] "EXP001" "EXP002" "EXP003"

Análisis comparativo

# Extraer todos los rendimientos rendimientos <- sapply( base_experimentos, function(x) x$rendimiento ) rendimientos # EXP001 EXP002 EXP003 # 85.3 78.2 45.1 # Calcular promedio mean(rendimientos) # [1] 69.53333 # Filtrar experimentos exitosos exitosos <- base_experimentos[ sapply(base_experimentos, function(x) x$exitoso) ] length(exitosos) # 2

Análisis avanzado

# Función para analizar la base completa analizar_experimentos <- function(base) { # Extraer variables temps <- sapply(base, function(x) x$temperatura) pHs <- sapply(base, function(x) x$pH) rends <- sapply(base, function(x) x$rendimiento) # Estadísticas cat("=== ANÁLISIS DE EXPERIMENTOS ===\n\n") cat("Total de experimentos:", length(base), "\n") cat("\nTemperatura:\n") cat(" Rango:", min(temps), "-", max(temps), "°C\n") cat(" Promedio:", mean(temps), "°C\n") cat("\npH:\n") cat(" Rango:", min(pHs), "-", max(pHs), "\n") cat(" Promedio:", mean(pHs), "\n") cat("\nRendimiento:\n") cat(" Promedio:", mean(rends), "%\n") cat(" Mejor:", max(rends), "%\n") cat(" Peor:", min(rends), "%\n") # Tasa de éxito n_exitosos <- sum(sapply(base, function(x) x$exitoso)) tasa_exito <- (n_exitosos / length(base)) * 100 cat("\nTasa de éxito:", tasa_exito, "%\n") } analizar_experimentos(base_experimentos)

Exportar a data frame para análisis

# Convertir a data frame para análisis estadístico df_experimentos <- do.call(rbind, lapply( base_experimentos, function(x) data.frame( nombre = x$nombre, temperatura = x$temperatura, pH = x$pH, rendimiento = x$rendimiento, exitoso = x$exitoso ) )) # Ahora podemos usar herramientas de data frame summary(df_experimentos) cor(df_experimentos$temperatura, df_experimentos$rendimiento)
10 / 15
Universidad Nacional de Costa Rica

Caso 3: almacenar resultados de análisis

Problema común

Los análisis estadísticos en R generan múltiples resultados: coeficientes, p-valores, residuos, predicciones, etc. Las listas son perfectas para almacenar todo esto.

Ejemplo: regresión lineal

# Datos de ejemplo temperatura <- c(20, 25, 30, 35, 40) rendimiento <- c(65, 72, 80, 75, 68) # Realizar regresión (retorna lista) modelo <- lm(rendimiento ~ temperatura) # Ver estructura del modelo class(modelo) # [1] "lm" names(modelo) # [1] "coefficients" "residuals" # [3] "effects" "rank" # [5] "fitted.values" "assign" # [7] "qr" "df.residual" # [9] "xlevels" "call" # [11] "terms" "model" # Es una lista nombrada especial is.list(modelo) # [1] TRUE

Acceso a resultados

# Coeficientes modelo$coefficients # (Intercept) temperatura # 66.00 0.20 # Residuos modelo$residuals # 1 2 3 4 5 # -5.0 2.0 6.0 -0.2 -6.8 # Valores ajustados modelo$fitted.values # 1 2 3 4 5 # 70.0 71.0 74.0 73.0 74.8

Crear análisis personalizado

# Función que retorna análisis completo analizar_relacion <- function(x, y, nombre_x = "X", nombre_y = "Y") { # Modelo de regresión modelo <- lm(y ~ x) # Crear lista de resultados resultados <- list( # Información básica variables = list( independiente = nombre_x, dependiente = nombre_y, n = length(x) ), # Datos originales datos = data.frame(x = x, y = y), # Modelo modelo = modelo, # Estadísticas clave estadisticas = list( r_cuadrado = summary(modelo)$r.squared, p_valor = summary(modelo)$coefficients[2, 4], pendiente = coef(modelo)[2], intercepto = coef(modelo)[1] ), # Diagnóstico diagnostico = list( residuos = resid(modelo), residuos_estandarizados = rstandard(modelo), valores_ajustados = fitted(modelo) ) ) # Asignar clase personalizada class(resultados) <- "analisis_regresion" return(resultados) } # Usar la función mi_analisis <- analizar_relacion( temperatura, rendimiento, "Temperatura (°C)", "Rendimiento (%)" )

Acceso organizado

# Información clara y estructurada mi_analisis$estadisticas$r_cuadrado mi_analisis$estadisticas$p_valor mi_analisis$variables$n # Crear función de resumen personalizada print.analisis_regresion <- function(x) { cat("=== ANÁLISIS DE REGRESIÓN ===\n\n") cat("Variables:\n") cat(" ", x$variables$independiente, "→", x$variables$dependiente, "\n") cat(" n =", x$variables$n, "\n\n") cat("Resultados:\n") cat(" R² =", round(x$estadisticas$r_cuadrado, 4), "\n") cat(" p-valor =", format.pval(x$estadisticas$p_valor), "\n") } print(mi_analisis)
11 / 15
Universidad Nacional de Costa Rica

Introducción a clases en R (sistema S3)

¿Qué son las clases?

En R, las clases permiten crear tipos de objetos personalizados con comportamientos específicos. El sistema S3 es el más simple y común.

Concepto básico

Una clase S3 es simplemente una lista con un atributo "class". Esto permite que funciones genéricas (como print(), summary(), plot()) se comporten de manera diferente según el tipo de objeto.

Crear un objeto con clase

# Función constructora crear_muestra <- function(id, compuesto, concentracion, pureza) { # Crear lista con datos muestra <- list( id = id, compuesto = compuesto, concentracion = concentracion, pureza = pureza, fecha_analisis = Sys.Date() ) # Asignar clase class(muestra) <- "muestra_quimica" return(muestra) } # Crear objeto m1 <- crear_muestra( id = "M001", compuesto = "NaCl", concentracion = 0.5, pureza = 99.8 ) class(m1) # [1] "muestra_quimica"

Crear método print personalizado

# Método print para nuestra clase print.muestra_quimica <- function(x, ...) { cat("╔════════════════════════════════════╗\n") cat("║ ANÁLISIS DE MUESTRA QUÍMICA ║\n") cat("╚════════════════════════════════════╝\n\n") cat("ID:", x$id, "\n") cat("Compuesto:", x$compuesto, "\n") cat("Concentración:", x$concentracion, "M\n") cat("Pureza:", x$pureza, "%\n") cat("Fecha:", format(x$fecha_analisis), "\n") cat("\n") } # Ahora al imprimir, usa nuestro método print(m1) # ╔════════════════════════════════════╗ # ║ ANÁLISIS DE MUESTRA QUÍMICA ║ # ╚════════════════════════════════════╝ # # ID: M001 # Compuesto: NaCl # Concentración: 0.5 M # Pureza: 99.8 % # Fecha: 2025-10-08

Método summary personalizado

summary.muestra_quimica <- function(object, ...) { cat("Resumen de muestra", object$id, "\n") cat("Compuesto:", object$compuesto, "\n") # Evaluación de calidad calidad <- if (object$pureza >= 99) { "Alta" } else if (object$pureza >= 95) { "Media" } else { "Baja" } cat("Calidad:", calidad, "\n") } summary(m1) # Resumen de muestra M001 # Compuesto: NaCl # Calidad: Alta

Ventaja de las clases

Las funciones genéricas automáticamente usan el método correcto según la clase del objeto

12 / 15
Universidad Nacional de Costa Rica

Ejercicio práctico 1: registro de estudiante

Desafío

Crea una lista nombrada que represente la información completa de un estudiante con las siguientes características:

Información a incluir:

  • Información personal: nombre, carné, carrera
  • Contacto: email, teléfono
  • Académico: vector de notas de 5 exámenes
  • Información calculada: promedio, estado (aprobado/reprobado)

Pasos

# 1. Crear la lista con toda la información # 2. Calcular el promedio de notas # 3. Determinar si aprobó (promedio >= 70) # 4. Imprimir información formateada

Ejemplo de salida esperada

# Al imprimir debería verse algo así: # # Estudiante: María López # Carné: B12345 # Carrera: Química Industrial # Email: maria.lopez@una.cr # # Notas: 85 78 92 88 90 # Promedio: 86.6 # Estado: APROBADO ✓

Solución

# Crear lista del estudiante estudiante <- list( # Información personal personal = list( nombre = "María López", carne = "B12345", carrera = "Química Industrial" ), # Contacto contacto = list( email = "maria.lopez@una.cr", telefono = "8888-9999" ), # Información académica academico = list( notas = c(85, 78, 92, 88, 90), promedio = NULL, # Lo calcularemos aprobado = NULL # Lo calcularemos ) ) # Calcular promedio estudiante$academico$promedio <- mean(estudiante$academico$notas) # Determinar si aprobó estudiante$academico$aprobado <- estudiante$academico$promedio >= 70 # Función para imprimir información mostrar_estudiante <- function(est) { cat("\nEstudiante:", est$personal$nombre, "\n") cat("Carné:", est$personal$carne, "\n") cat("Carrera:", est$personal$carrera, "\n") cat("Email:", est$contacto$email, "\n\n") cat("Notas:", est$academico$notas, "\n") cat("Promedio:", round(est$academico$promedio, 1), "\n") estado <- ifelse(est$academico$aprobado, "APROBADO ✓", "REPROBADO ✗") cat("Estado:", estado, "\n") } mostrar_estudiante(estudiante)

Extensión del ejercicio

Agrega funcionalidad para:

  • Calcular la nota máxima y mínima
  • Agregar una nueva nota
  • Recalcular el promedio automáticamente
13 / 15
Universidad Nacional de Costa Rica

Ejercicio práctico 2: base de datos de compuestos

Desafío

Crea una base de datos de compuestos químicos usando una lista de listas nombradas. Cada compuesto debe tener propiedades específicas.

Información de cada compuesto:

  • Nombre y fórmula química
  • Masa molar (g/mol)
  • Punto de fusión (°C)
  • Punto de ebullición (°C)
  • Solubilidad en agua (g/L)
  • Clasificación (ácido, base, sal, orgánico)

Tareas

# 1. Crear base con al menos 4 compuestos # 2. Función: buscar por nombre # 3. Función: filtrar por clasificación # 4. Función: encontrar compuesto con # mayor punto de ebullición # 5. Función: calcular masa molar promedio

Solución

# Base de datos de compuestos compuestos_db <- list( COMP001 = list( nombre = "Cloruro de sodio", formula = "NaCl", masa_molar = 58.44, pto_fusion = 801, pto_ebullicion = 1413, solubilidad = 360, clasificacion = "sal" ), COMP002 = list( nombre = "Ácido clorhídrico", formula = "HCl", masa_molar = 36.46, pto_fusion = -114, pto_ebullicion = -85, solubilidad = 720, clasificacion = "acido" ), COMP003 = list( nombre = "Hidróxido de sodio", formula = "NaOH", masa_molar = 40.00, pto_fusion = 318, pto_ebullicion = 1388, solubilidad = 1110, clasificacion = "base" ), COMP004 = list( nombre = "Etanol", formula = "C2H5OH", masa_molar = 46.07, pto_fusion = -114, pto_ebullicion = 78, solubilidad = 1000, clasificacion = "organico" ) ) # Función 1: Buscar por nombre buscar_compuesto <- function(db, nombre_buscar) { for (id in names(db)) { if (grepl(nombre_buscar, db[[id]]$nombre, ignore.case = TRUE)) { return(db[[id]]) } } return(NULL) } # Función 2: Filtrar por clasificación filtrar_por_clase <- function(db, clase) { db[sapply(db, function(x) x$clasificacion == clase)] } # Función 3: Mayor punto de ebullición max_ebullicion <- function(db) { ebulliciones <- sapply(db, function(x) x$pto_ebullicion) id_max <- which.max(ebulliciones) return(db[[id_max]]) } # Función 4: Masa molar promedio masa_promedio <- function(db) { masas <- sapply(db, function(x) x$masa_molar) return(mean(masas)) } # Usar las funciones sal <- buscar_compuesto(compuestos_db, "sodio") acidos <- filtrar_por_clase(compuestos_db, "acido") mas_volatil <- max_ebullicion(compuestos_db) promedio_masas <- masa_promedio(compuestos_db)
14 / 15
Universidad Nacional de Costa Rica

Resumen y mejores prácticas

Conceptos clave aprendidos

Listas en R

  • Estructura más flexible de R
  • Puede contener cualquier tipo de objeto
  • Ideal para datos heterogéneos

Listas nombradas

  • Equivalente a diccionarios de Python
  • Acceso mediante nombres descriptivos
  • Código más legible y mantenible
  • Uso del operador $ para acceso directo

Clases S3

  • Listas con atributo "class"
  • Permiten métodos personalizados
  • Sistema simple pero poderoso
  • Comportamiento especializado por tipo

Cuándo usar cada estructura

Usa vectores cuando:

  • Todos los datos son del mismo tipo
  • Necesitas operaciones matemáticas simples

Usa data frames cuando:

  • Datos tabulares (observaciones × variables)
  • Análisis estadístico estándar

Usa listas cuando:

  • Datos heterogéneos y complejos
  • Estructuras jerárquicas
  • Resultados de análisis múltiples
  • Necesitas flexibilidad máxima

Mejores prácticas

Nomenclatura clara

# ❌ Malo l <- list(a = 1, b = 2, c = 3) # ✓ Bueno experimento <- list( temperatura = 25, presion = 1.0, pH = 7.0 )

Validación de entrada

crear_muestra <- function(id, conc) { # Validar entradas if (!is.character(id)) { stop("ID debe ser texto") } if (!is.numeric(conc) || conc < 0) { stop("Concentración debe ser numérica positiva") } # Crear objeto list(id = id, concentracion = conc) }

Documentación

# Documentar estructura de listas complejas experimento <- list( # Metadatos del experimento metadata = list(...), # Condiciones experimentales condiciones = list(...), # Datos de mediciones datos = data.frame(...), # Resultados del análisis resultados = list(...) )

Errores comunes a evitar

# ❌ Error 1: Confundir [] con [[]] lista <- list(a = 1:3) lista[1] # Retorna sublista lista[[1]] # Retorna el vector # ❌ Error 2: Olvidar names() en loops for (nombre in names(lista)) { # ✓ Correcto # usar nombre } # ❌ Error 3: No verificar NULL if (!is.null(lista$elemento)) { # ✓ Correcto # procesar elemento }

Recursos adicionales

Para profundizar:

  • Advanced R (Hadley Wickham) - Capítulo sobre OOP
  • R for Data Science - Capítulo sobre listas
  • Documentación: ?list, ?class
  • Tutoriales sobre sistemas S3, S4, R6
"Las listas son la navaja suiza de R: cuando necesites flexibilidad y organización, son tu mejor herramienta"
15 / 15