¿Cómo extraer nombres y valores de listas?
Si vienes del mundo de Python y estás comenzando a trabajar con R para análisis de datos deportivos, una de las primeras dificultades que encontrarás es cómo manejar estructuras de datos similares a los diccionarios de Python. En R, estas estructuras se llaman listas con nombres (named lists), y trabajar con ellas requiere entender algunas funciones clave.
Esta guía te mostrará cómo extraer información de listas en R usando la notación completa de paquetes, fundamental para escribir código reproducible y profesional.
📚 Traductor: terminología Python → R
Antes de comenzar, aquí está tu "diccionario de traducción" para entender las equivalencias:
| Concepto Python | Equivalente R | Función/Sintaxis | Explicación |
|---|---|---|---|
dict |
list() con nombres |
list(a=1, b=2) |
Lista con elementos nombrados |
dict.keys() |
names() |
base::names(lista) |
Extraer nombres/llaves |
dict.values() |
unlist() |
base::unlist(lista) |
Extraer valores (mismo tipo) |
dict.items() |
tibble::enframe() |
tibble::enframe(lista) |
Crear pares nombre-valor |
dict['key'] |
lista[["key"]] |
lista[["nombre"]] |
Acceso directo a elemento |
list(dict.items()) |
tibble::tibble() |
tibble::tibble(names, values) |
Convertir a tabla |
Nota sobre namespaces: siempre es recomendable agregar el prefijo de namespace (o prefijo de paquete) a todas las funciones, usando la notación paquete::funcion() para:
- Evitar conflictos entre funciones con el mismo nombre
- Hacer el código más claro y autodocumentado
- Facilitar la reproducibilidad
🎯 Caso 1: extraer solo los nombres
Cuando solo necesitas las "llaves" de tu estructura (equivalente a dict.keys() en Python), usa base::names():
Sintaxis básica
# Cargar librería (aunque names() es de base, es buena práctica)
library(tibble)
# Tu lista (similar a un diccionario de Python)
mi_lista <- list(
nombre = "Juan",
edad = 30,
ciudad = "Madrid",
puntuacion = 85.5
)
# Extraer solo los nombres usando función de base R
nombres <- base::names(mi_lista)
print(nombres)
# [1] "nombre" "edad" "ciudad" "puntuacion"
¿Qué devuelve?
Tipo de dato: Vector de caracteres (character vector)
Características:
- Es un vector simple, no una lista
- Mantiene el orden original de la lista
- Útil para iteraciones o validaciones
Ejemplo práctico: validación de campos
# Lista con datos de un partido de fútbol
datos_partido <- list(
match_id = 3399385,
fecha = "2020-12-04",
equipo_local = "Bayern Munich",
equipo_visitante = "Borussia Dortmund",
goles_local = 3,
goles_visitante = 2
)
# Campos requeridos para nuestro análisis
campos_requeridos <- c("match_id", "fecha", "equipo_local", "equipo_visitante")
# Verificar que todos los campos existen
campos_disponibles <- base::names(datos_partido)
campos_faltantes <- base::setdiff(campos_requeridos, campos_disponibles)
if (base::length(campos_faltantes) == 0) {
print("✅ Todos los campos requeridos están presentes")
} else {
print(base::paste("❌ Faltan campos:", base::paste(campos_faltantes, collapse = ", ")))
}
🎯 Caso 2: crear pares nombre-valor con tibble::tibble()
Cuando necesitas una estructura tabular con pares nombre-valor (equivalente a pd.DataFrame(dict.items()) en pandas), tienes dos métodos principales:
Método 1: Manual con base::names() + base::unlist()
library(tibble)
mi_lista <- list(
nombre = "Juan",
edad = 30,
ciudad = "Madrid",
puntuacion = 85.5
)
# Crear tibble manualmente
pares_nv <- tibble::tibble(
nombre = base::names(mi_lista),
valor = base::unlist(mi_lista, use.names = FALSE)
)
print(pares_nv)
# # A tibble: 4 × 2
# nombre valor
# <chr> <chr>
# 1 nombre Juan
# 2 edad 30
# 3 ciudad Madrid
# 4 puntuacion 85.5
Ventajas:
- Control total sobre el proceso
- No requiere paquetes adicionales (además de tibble)
- Fácil de entender para principiantes
Desventajas:
base::unlist()convierte todo a un solo tipo (generalmentecharacter)- Pierdes información de tipos de datos originales
- Más verboso
Método 2: Usando tibble::enframe() (Recomendado)
library(tibble)
library(tidyr)
mi_lista <- list(
nombre = "Juan",
edad = 30,
ciudad = "Madrid",
puntuacion = 85.5
)
# enframe() convierte directamente lista a tibble
pares_nv <- mi_lista |>
tibble::enframe(name = "campo", value = "valor") |>
tidyr::unnest(valor)
print(pares_nv)
# # A tibble: 4 × 2
# campo valor
# <chr> <chr>
# 1 nombre Juan
# 2 edad 30
# 3 ciudad Madrid
# 4 puntuacion 85.5
Ventajas:
- Más idiomático y legible en R moderno
- Maneja mejor listas anidadas
- Se integra perfectamente con el tidyverse
- Menos código
Desventajas:
- Requiere dos paquetes (tibble + tidyr)
- Puede ser menos intuitivo para principiantes
🛠️ Ejemplos prácticos con datos deportivos
Ejemplo 1: Procesar datos de un partido Individual
library(tibble)
library(dplyr)
library(tidyr)
# Datos típicos que podrías recibir de una API de fútbol
datos_partido <- list(
match_id = 3399385,
fecha = "2020-12-04",
equipo_local = "Bayern Munich",
equipo_visitante = "Borussia Dortmund",
goles_local = 3,
goles_visitante = 2,
estadio = "Allianz Arena",
asistencia = 75000
)
# Método 1: Solo extraer nombres de campos
nombres_campos <- base::names(datos_partido)
print("📋 Campos disponibles:")
print(nombres_campos)
# Método 2: Crear tabla de metadatos
tabla_metadatos <- datos_partido |>
tibble::enframe(name = "campo", value = "valor") |>
tidyr::unnest(valor) |>
dplyr::mutate(
tipo = base::class(valor),
longitud = base::nchar(base::as.character(valor))
)
print(tabla_metadatos)
# # A tibble: 8 × 4
# campo valor tipo longitud
# <chr> <chr> <chr> <int>
# 1 match_id 3399385 numeric 7
# 2 fecha 2020-12-04 character 10
# 3 equipo_local Bayern Munich character 13
# 4 equipo_visitante Borussia Dortmund character 17
# ...
Ejemplo 2: Procesar múltiples partidos
library(tibble)
library(purrr)
library(dplyr)
# Lista de partidos (estructura típica de API)
lista_partidos <- list(
partido1 = list(
match_id = 123,
goles = 3,
equipo = "Barcelona",
fecha = "2024-01-15"
),
partido2 = list(
match_id = 124,
goles = 1,
equipo = "Real Madrid",
fecha = "2024-01-16"
),
partido3 = list(
match_id = 125,
goles = 2,
equipo = "Atlético Madrid",
fecha = "2024-01-17"
)
)
# Opción 1: Extraer solo identificadores de partidos
nombres_partidos <- base::names(lista_partidos)
print("🏆 Identificadores de partidos:")
print(nombres_partidos)
# [1] "partido1" "partido2" "partido3"
# Opción 2: Crear tabla completa con todos los datos
tabla_partidos <- lista_partidos |>
purrr::map_dfr(
~ tibble::tibble(
match_id = .x$match_id,
goles = .x$goles,
equipo = .x$equipo,
fecha = .x$fecha
),
.id = "partido_key"
)
print(tabla_partidos)
# # A tibble: 3 × 5
# partido_key match_id goles equipo fecha
# <chr> <dbl> <dbl> <chr> <chr>
# 1 partido1 123 3 Barcelona 2024-01-15
# 2 partido2 124 1 Real Madrid 2024-01-16
# 3 partido3 125 2 Atlético Madrid 2024-01-17
# Opción 3: Extraer solo match_ids (más eficiente)
match_ids <- lista_partidos |>
purrr::map_dbl("match_id") # map_dbl garantiza tipo numérico
print(match_ids)
# partido1 partido2 partido3
# 123 124 125
Ejemplo 3: Trabajar con datos anidados de API
library(tibble)
library(tidyr)
library(dplyr)
library(purrr)
# Estructura compleja típica de respuesta de API
respuesta_api <- list(
metadata = list(
request_id = "abc123",
timestamp = "2024-10-22T10:30:00Z",
endpoint = "/api/matches"
),
data = list(
match_id = 3399385,
teams = list(
home = "Bayern Munich",
away = "Borussia Dortmund"
),
score = list(
home = 3,
away = 2
)
)
)
# Extraer estructura de metadatos
estructura_metadata <- respuesta_api$metadata |>
tibble::enframe(name = "campo_metadata", value = "valor_metadata") |>
tidyr::unnest(valor_metadata)
print("📊 Metadatos de la API:")
print(estructura_metadata)
# Extraer datos del partido
datos_partido_limpio <- tibble::tibble(
match_id = respuesta_api$data$match_id,
equipo_local = respuesta_api$data$teams$home,
equipo_visitante = respuesta_api$data$teams$away,
goles_local = respuesta_api$data$score$home,
goles_visitante = respuesta_api$data$score$away
)
print("⚽ Datos del partido:")
print(datos_partido_limpio)
⚠️ Consideraciones importantes y errores comunes
1. El Problema de base::unlist() con tipos de datos
library(tibble)
# Lista con diferentes tipos de datos
datos_mixtos <- list(
nombre = "Leo Messi",
edad = 37,
activo = TRUE,
goles_temporada = 25
)
# ❌ MAL: Usar unlist() sin precaución
valores_unlist <- base::unlist(datos_mixtos)
print(valores_unlist)
# nombre edad activo goles_temporada
# "Leo Messi" "37" "TRUE" "25"
# ☝️ Todo se convirtió a character!
# ✅ BIEN: Usar enframe() + unnest() preserva tipos
valores_correcto <- datos_mixtos |>
tibble::enframe(name = "campo", value = "valor") |>
tidyr::unnest(valor)
print(valores_correcto)
# # A tibble: 4 × 2
# campo valor
# <chr> <list>
# 1 nombre <chr [1]>
# 2 edad <dbl [1]>
# 3 activo <lgl [1]>
# 4 goles_temporada <dbl [1]>
2. Listas anidadas requieren estrategia diferente
library(tibble)
library(tidyr)
library(purrr)
# Lista con estructura anidada
equipo_completo <- list(
equipo = "Barcelona",
jugadores = list(
delantero = "Lewandowski",
mediocampista = "Gundogan"
),
estadisticas = list(
goles = 85,
asistencias = 42
)
)
# ❌ MAL: enframe() simple no maneja bien la anidación
intento_simple <- equipo_completo |>
tibble::enframe()
# Resultado: Columna "value" sigue siendo lista
# ✅ BIEN: Necesitas unnest() más profundo o flatten
datos_aplanados <- equipo_completo |>
purrr::list_flatten() |> # Aplana un nivel
tibble::enframe(name = "campo", value = "valor") |>
tidyr::unnest(valor)
print(datos_aplanados)
3. Performance: tibble::tibble() vs base::data.frame()
library(tibble)
library(microbenchmark)
# Comparar rendimiento
mi_lista_grande <- base::as.list(base::setNames(1:10000, base::paste0("var", 1:10000)))
comparacion <- microbenchmark::microbenchmark(
con_tibble = {
tibble::tibble(
nombre = base::names(mi_lista_grande),
valor = base::unlist(mi_lista_grande, use.names = FALSE)
)
},
con_dataframe = {
base::data.frame(
nombre = base::names(mi_lista_grande),
valor = base::unlist(mi_lista_grande, use.names = FALSE)
)
},
times = 100
)
print(comparacion)
# tibble() es generalmente 2-3x más rápido para datos grandes
4. Manejo de valores NULL
library(tibble)
library(tidyr)
library(purrr)
# Lista con algunos valores NULL (común en APIs)
datos_incompletos <- list(
match_id = 123,
goles_local = 3,
goles_visitante = NULL, # Dato faltante
asistencia = 50000,
arbitro = NULL # Dato faltante
)
# ❌ MAL: unlist() elimina los NULL sin aviso
valores_unlist <- base::unlist(datos_incompletos)
print(base::length(valores_unlist)) # Solo 3 elementos (perdiste 2)
# ✅ BIEN: enframe() + unnest() con keep_empty
valores_completo <- datos_incompletos |>
tibble::enframe(name = "campo", value = "valor") |>
tidyr::unnest(valor, keep_empty = TRUE)
print(valores_completo)
# # A tibble: 5 × 2
# campo valor
# <chr> <list>
# 1 match_id <dbl [1]>
# 2 goles_local <dbl [1]>
# 3 goles_visitante <NULL> ← Se preserva
# 4 asistencia <dbl [1]>
# 5 arbitro <NULL> ← Se preserva
📊 Comparación de métodos: ¿cuál usar?
| Método | Velocidad | Preserva Tipos | Maneja Anidación | Complejidad Código | Uso Recomendado |
|---|---|---|---|---|---|
base::names() |
⚡⚡⚡ | N/A | N/A | Muy Simple | Solo necesitas nombres |
base::unlist() |
⚡⚡⚡ | ❌ | Limitada | Simple | Datos homogéneos simples |
tibble::tibble() manual |
⚡⚡ | ❌ | No | Moderada | Control total del proceso |
tibble::enframe() |
⚡⚡ | ✅ | ✅ | Simple | Recomendado para la mayoría de casos |
purrr::map_dfr() |
⚡ | ✅ | ✅ | Alta | Listas de listas complejas |
🎓 Para profundizar
Si quieres dominar completamente el manejo de listas en R, estos son los conceptos avanzados a estudiar:
- purrr::pluck(): Extracción segura de elementos anidados
- purrr::keep() / purrr::discard(): Filtrado de listas
- purrr::list_modify(): Modificación de listas
- rlang::list2(): Creación dinámica de listas nombradas
- jsonlite::fromJSON(): Conversión JSON → listas R
Conclusión: La transición de diccionarios Python a listas R es más suave de lo que parece. La clave está en entender que tibble::enframe() es tu mejor amigo para la mayoría de casos, y siempre usar la notación paquete::funcion() para código profesional y reproducible.
¿Trabajas con APIs deportivas en R? Estos patrones te ahorrarán horas de frustración. ¡Guarda este artículo como referencia!

Comentarios
Publicar un comentario