Capítulo17 Tibbles
Fecha de la última revisión
## [1] "2026-10-08"
El tema proviene de los siguientes sitios.
English: https://r4ds.had.co.nz/tibbles.html
Español: https://es.r4ds.hadley.nz/10-tibble.html
17.1 Temas: El paquete Tibble
Los tibble son la versión moderna del data.frame dentro del tidyverse: hacen menos «magia» automática (no cambian nombres ni tipos de columna) y ofrecen una impresión más legible en la consola.
- Por qué existe el tibble
- Crear tablas:
tibble(),tribble(),as_tibble() - Cómo se imprime un tibble, y cómo pedirle que imprima más
- Las cuatro diferencias con el
data.frameque de verdad importan - Sacar una columna:
$,[[,[y el marcador. - Cuándo hay que volver a un
data.frame
17.3 ¿Por qué existe el tibble?
El data.frame es de 1990 y se diseñó cuando las tablas cabían en una pantalla.
Con los años se le fueron acumulando comportamientos que en su momento eran
cómodos y que hoy hacen perder tiempo:
imprime la tabla entera en la consola, así que un archivo de 50 000 filas llena la pantalla y hay que subir a buscar el principio;
hace coincidencia parcial de nombres: si le pides
df$ay la única columna que empieza por “a” esabc, te la da sin avisar, y una errata pasa por buena;durante muchos años convertía el texto en factores por su cuenta, y arreglaba los nombres de columna sin decirlo;
guarda nombres de fila, que son datos escondidos fuera de las columnas.
El tibble hace lo mismo que el data.frame pero sin la magia: imprime poco,
no adivina nombres, no cambia tipos y no guarda nombres de fila. Se queja cuando
hay algo raro en vez de arreglarlo en silencio, y eso es exactamente lo que uno
quiere de una herramienta de análisis.
Un tibble es un data frame: is.data.frame(mi_tibble) devuelve TRUE. Todo
lo que funciona con un data frame funciona con un tibble. Al revés no siempre,
y de eso trata la última sección del capítulo.
17.4 Crear un tibble
tibble(), tribble(), as_tibble(): crear tablas modernas.
tibble(col = valores, ...): crea un tibble por columnas.tribble(~col1, ~col2, v, v, ...): lo crea fila por fila (cómodo para tablas pequeñas escritas a mano).as_tibble(df): convierte undata.frameen tibble.
tibble() construye la tabla por columnas: cada argumento es un vector, y
todos tienen que tener el mismo largo (o largo 1, que se repite). A diferencia de
data.frame(), no toca los nombres, no convierte el texto en factores y no
recicla vectores de largo raro.
Crear un tibble con la siguiente información. Una columna que tiene los valores del 1 al 8 que se llama “secuencia”, una segunda columna que tiene los siguientes valores 23,26, 24,26,27, 11,20,21 que se llama edad y una tercera columna con la siguiente información, Jose, Maria, Carol, Moncho, Liz, Maria, Jorge, Miguel, que se llama Nombre
El bloque de abajo construye solo las seis primeras filas de las ocho que
pide el enunciado, y deja un NA en la última edad. Completarlo es el primer
ejercicio del capítulo.
tibble(
secuencia = 1:6,
edad = c(23, 26, 24, 26, 27, NA),
nombre = c("Jose", "Maria", "Carol", "Moncho", "Liz", "Maria")
)## # A tibble: 6 × 3
## secuencia edad nombre
## <int> <dbl> <chr>
## 1 1 23 Jose
## 2 2 26 Maria
## 3 3 24 Carol
## 4 4 26 Moncho
## 5 5 27 Liz
## 6 6 NA Maria
17.5 Crear un tribble
tribble() construye la tabla fila por fila, que es como uno la escribiría a
mano en una libreta. Los nombres de las columnas van con una virgulilla delante
(~secuencia), y después vienen los valores en el mismo orden. Es la forma más
cómoda de meter en un script una tabla pequeña: los datos de un experimento, una
tabla de equivalencias, los códigos de las parcelas.
Alinea los valores en columnas cuando escribas un tribble(). No cambia nada
para R, pero hace que un dato fuera de sitio salte a la vista.
Haga un tribble con las primeras 3 líneas del tibble anterior
## # A tibble: 3 × 3
## secuencia edad nombre
## <dbl> <dbl> <chr>
## 1 1 23 Jose
## 2 2 26 Maria
## 3 3 23 Carol
17.6 tibble vs. data.frame
El bloque siguiente construye una tabla de 100 filas y la imprime de las dos
maneras. Compara la salida: el tibble enseña diez filas, el tipo de cada
columna debajo del nombre (<dttm>, <date>, <int>, <dbl>, <chr>) y una
nota de cuántas filas quedaron sin imprimir.
Esa línea con los tipos es la razón principal para preferir el tibble mientras se explora: la mitad de los problemas de un análisis son una columna que uno creía numérica y era texto, y aquí se ve sin tener que pedir nada.
El data frame no hace nada de eso. Si escribes df_tb a secas, te suelta las cien
filas de golpe. Por eso aquí va envuelto en head(), que es la manera corta de
decir “enséñame el principio y ya”. Prueba una vez en tu consola a escribirlo sin
head(), para ver lo que te estás ahorrando, y no lo dejes así en ningún
documento que vayas a entregar.
set.seed(2026)
tb <- tibble(
a = lubridate::now() + runif(1e2) * 86400,
b = lubridate::today() + runif(1e2) * 30,
c = 1:100,
d = runif(1e2),
e = sample(letters, 1e2, replace = TRUE)
)
tb## # A tibble: 100 × 5
## a b c d e
## <dttm> <date> <int> <dbl> <chr>
## 1 2026-10-09 04:26:39 2026-10-11 1 0.888 b
## 2 2026-10-09 01:01:58 2026-11-01 2 0.630 m
## 3 2026-10-08 15:02:21 2026-10-20 3 0.311 l
## 4 2026-10-08 18:32:00 2026-10-10 4 0.963 z
## 5 2026-10-09 01:00:17 2026-10-13 5 0.410 g
## 6 2026-10-08 12:16:45 2026-10-13 6 0.748 m
## 7 2026-10-08 22:51:56 2026-10-28 7 0.133 o
## 8 2026-10-09 08:20:25 2026-10-26 8 0.969 a
## 9 2026-10-08 17:44:09 2026-10-15 9 0.840 y
## 10 2026-10-09 01:36:55 2026-10-25 10 0.575 n
## # ℹ 90 more rows
## a b c d e
## 1 2026-10-09 04:26:39 2026-10-11 1 0.8880583 b
## 2 2026-10-09 01:01:58 2026-11-01 2 0.6304131 m
## 3 2026-10-08 15:02:21 2026-10-20 3 0.3107084 l
## 4 2026-10-08 18:32:00 2026-10-10 4 0.9632153 z
## 5 2026-10-09 01:00:17 2026-10-13 5 0.4099068 g
## 6 2026-10-08 12:16:45 2026-10-13 6 0.7481300 m
## 7 2026-10-08 22:51:56 2026-10-28 7 0.1331446 o
## 8 2026-10-09 08:20:25 2026-10-26 8 0.9693217 a
## 9 2026-10-08 17:44:09 2026-10-15 9 0.8403344 y
## 10 2026-10-09 01:36:55 2026-10-25 10 0.5746544 n
head(), tail(), slice_head(), slice_sample() y glimpse(): mirar una
tabla sin inundar la pantalla.
head(tabla, n = 10): las primerasnfilas. Funciona igual con un vector.tail(tabla, n = 10): las últimas. Es la forma rápida de comprobar que un archivo se leyó completo y no se cortó a la mitad.slice_head(tabla, n = 10): la versión del tidyverse, que encaja en un pipe y respeta los grupos degroup_by().slice_sample(tabla, n = 10): diez filas al azar. Muchas veces enseña más que las diez primeras, porque las primeras suelen venir ordenadas y no son representativas.glimpse(tabla): una línea por columna, con el tipo y los primeros valores. Es lo mejor cuando hay muchas columnas y la impresión normal las corta a lo ancho.
En un documento que vayas a entregar, nunca dejes un bloque que imprima una
tabla completa. Un data frame de 50 000 filas produce 50 000 líneas en el .html,
el archivo se vuelve pesadísimo y el lector no encuentra nada. Usa head(),
glimpse() o print(n = ...). Y deja View() para cuando estés trabajando en
RStudio: abre la tabla en una ventana aparte y no imprime nada en el documento.
El set.seed(2026) del principio del bloque fija el azar de runif() y de
sample(), para que la tabla salga igual cada vez que se construya el libro. Sin
esa línea, cada knit produciría números distintos.
Cuando de verdad hacen falta más filas o más columnas, se piden:
print() en un tibble: decidir cuánto se imprime.
print(n = 4): cuatro filas en vez de diez.n = Inflas imprime todas.width = Inf: todas las columnas, aunque no quepan a lo ancho.View(tabla): abre la tabla completa en una ventana de RStudio, que casi siempre es lo que uno quería.
## # A tibble: 100 × 5
## a b c d e
## <dttm> <date> <int> <dbl> <chr>
## 1 2026-10-09 04:26:39 2026-10-11 1 0.888 b
## 2 2026-10-09 01:01:58 2026-11-01 2 0.630 m
## 3 2026-10-08 15:02:21 2026-10-20 3 0.311 l
## 4 2026-10-08 18:32:00 2026-10-10 4 0.963 z
## # ℹ 96 more rows
Y cuando lo que estorba no son las filas sino las columnas, la salida que
conviene es la de glimpse(), que gira la tabla y pone una línea por columna:
## Rows: 100
## Columns: 5
## $ a <dttm> 2026-10-09 04:26:39, 2026-10-09 01:01:58, 2026-10-08 15:02:21, 2026…
## $ b <date> 2026-10-11, 2026-11-01, 2026-10-20, 2026-10-10, 2026-10-13, 2026-10…
## $ c <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2…
## $ d <dbl> 0.88805829, 0.63041310, 0.31070844, 0.96321527, 0.40990680, 0.748129…
## $ e <chr> "b", "m", "l", "z", "g", "m", "o", "a", "y", "n", "z", "d", "c", "p"…
Para convertir un data frame en tibble se usa
as_tibble().Para convertir un tibble en data frame se usa
as.data.frame().
as_tibble() y as.data.frame(): pasar de un formato al otro.
as_tibble(df): envuelve un data frame como tibble. No copia los datos ni los cambia; solo cambia cómo se imprime y cómo se comporta.as.data.frame(tb): el camino de vuelta. Hace falta cuando una función vieja no acepta tibbles.- Ojo con los nombres de fila:
as_tibble()los descarta. Si los necesitas, guárdalos antes en una columna contibble::rownames_to_column().
17.7 Diferencias entre un tibble y un data frame
Son cuatro, y conviene tenerlas presentes porque explican casi todos los tropiezos del principio.
1. La impresión.
- Tibbles tiene un buen método de impresión que muestra solo las primeras 10 filas y todas las columnas que caben en la pantalla.
- Tibbles no admite nombres de filas. Se eliminan al convertir a tibble o al crear subconjuntos:
2. Operaciones aritméticas en tibbles.
A diferencia de los data frame, los tibbles NO admiten operaciones aritméticas en todas las columnas: el resultado se fuerza silenciosamente a un data frame.
Es decir: multiplicar la tabla entera por 2 funciona, pero lo que sale ya no es
un tibble. No es un problema grave, pero sí explica por qué a veces una tabla
“deja de imprimirse bonito” en medio de un análisis. La manera correcta de hacer
aritmética sobre una tabla es columna por columna, con mutate(), como en el
segundo bloque.
## [1] FALSE
## [1] TRUE
## # A tibble: 3 × 3
## a b c
## <int> <int> <dbl>
## 1 1 4 8
## 2 2 5 10
## 3 3 6 12
## [1] TRUE
3. Nada de coincidencias parciales.
- Los tibbles también son más estrictos con
$. Tibbles nunca realiza coincidencias parciales y generará una advertencia y devolveráNULLsi la columna no existe:
df <- data.frame(abc = 1)
df2 <- tibble(abc = 1)
df$abc # el nombre completo: funciona igual en los dos## [1] 1
## [1] 1
Ahora la comparación que importa. La misma errata, $a en vez de $abc, en las
dos clases de tabla:
## [1] 1
## Warning: Unknown or uninitialised column: `a`.
## NULL
Este es el mejor argumento a favor del tibble. En un data frame, escribir mal el
nombre de una columna puede devolverte otra columna sin decir nada, y el
análisis sigue con la variable equivocada. El tibble te devuelve NULL y una
advertencia, así que el error aparece de inmediato.
4. Sacar una columna: $, [[ y [.
- Para extraer una columna de un tibble se usa
[[. Es más seguro que$porque acepta el nombre como texto y nunca hace coincidencias parciales:
$, [[ y [: tres maneras de sacar datos de una tabla, y no dan lo mismo.
tabla$columna: devuelve el vector. Cómodo, pero el nombre va escrito directamente en el código.tabla[["columna"]]: devuelve el vector. Acepta el nombre entre comillas o el número de posición, así que sirve dentro de una función o de un bucle.tabla["columna"]: con un solo corchete devuelve una tabla de una columna, no un vector. En un data frame,df[, "columna"]devuelve un vector; en un tibble devuelve un tibble, y esa diferencia rompe código viejo.- Dentro de un pipe de magrittr:
tabla %>% .$columnaotabla %>% .[["columna"]], donde el punto es la tabla que viene por el pipe.
17.8 Selección de subconjuntos de datos
El bloque siguiente saca la misma columna de vuelos de cuatro maneras
distintas, dos directas y dos dentro de un pipe, más la que conviene usar. Todas
devuelven exactamente lo mismo; están juntas para que reconozcas las cinco cuando
las veas en código ajeno.
Fíjate en que cada una termina en head(n = 5). La columna salida_programada
tiene más de 300 000 valores: sin ese head() el documento quedaría inservible.
En una cadena del tidyverse casi siempre es mejor pull(columna) que .$columna:
hace lo mismo, se lee mejor y funciona igual con el pipe nativo.
## [1] 515 529 540 545 600
## [1] 515 529 540 545 600
## [1] 515 529 540 545 600
## [1] 515 529 540 545 600
## [1] 515 529 540 545 600
17.9 Cuándo hay que volver a un data.frame
Casi todo el código de R moderno acepta tibbles sin problema. Los que no, son
paquetes viejos que suponen que tabla[, "columna"] devuelve un vector, o que
esperan nombres de fila. Cuando una función se queja de forma rara, la prueba
rápida es pasarle as.data.frame(mi_tibble) y ver si el problema desaparece.
El data.frame viene del lenguaje S, de los Laboratorios Bell, y pasó a R
casi sin cambios. El paquete tibble lo reescribió en 2016, dentro del
tidyverse liderado por Hadley Wickham, con una regla explícita: “hacer menos
y quejarse más”. La palabra tibble sale de cómo suena “tbl”, la abreviatura
que ya usaba dplyr para sus tablas.
17.11 Ejercicios del capítulo
Sobre los ejercicios de este capítulo. Cada ejercicio se entrega con tres
cosas: el script, el resultado (que el bloque corra) y una explicación
en palabras. Los ejercicios usan millas y paises del paquete datos, y
tablas que escribirás a mano, no vuelos, que es el conjunto del capítulo. La
hoja completa para entregar está en Ejercicios/Ejercicios_Capitulo_17_tibbles.Rmd.
17.11.1 Ejercicio 1. Completar el tibble
El bloque del principio del capítulo construye solo seis de las ocho filas que
pedía el enunciado. Complétalo: secuencia del 1 al 8; edad con 23, 26, 24,
26, 27, 11, 20, 21; y nombre con Jose, Maria, Carol, Moncho, Liz, Maria, Jorge
y Miguel.
Verificación: tu tibble debe tener 8 filas y 3 columnas, y la línea de tipos
debe decir <int> o <dbl> para las dos primeras y <chr> para la tercera.
En palabras: ¿qué pasa si le das a una columna siete valores en vez de ocho?
Pruébalo en un bloque con error=TRUE y explica el mensaje. ¿Por qué sí
funciona si le das uno solo?
17.11.2 Ejercicio 2. Una tabla escrita a mano
Con tribble(), escribe una tabla de cuatro parcelas de campo con tres
columnas: parcela (texto), n_plantas (número entero) y humedad (texto:
“alta” o “baja”). Invéntate los valores.
Verificación: 4 filas, 3 columnas, y los tipos correctos en la línea de tipos.
En palabras: ¿en qué situación preferirías tribble() a tibble()? Da un
ejemplo de tu propio trabajo o de la clase.
17.11.3 Ejercicio 3. Ida y vuelta
Convierte millas en data frame con as.data.frame(), guárdalo, y conviértelo
otra vez en tibble con as_tibble(). Comprueba las dos veces con is_tibble() y
con is.data.frame().
Verificación: is.data.frame() da TRUE en los tres objetos;
is_tibble() solo en dos de los tres.
En palabras: ¿por qué is.data.frame() dice TRUE incluso para el tibble?
¿Qué relación hay entre las dos clases?
17.11.4 Ejercicio 4. Imprimir lo justo
Imprime paises de cuatro maneras: tal cual, con print(n = 3), con
print(n = Inf, width = Inf) (no lo hagas dentro del documento final, es
enorme), y como data frame con as.data.frame(paises).
Verificación: la impresión normal enseña 10 filas y dice cuántas quedaron fuera.
En palabras: además del número de filas, ¿qué información te da el tibble que el data frame no te da? ¿Por qué esa información ahorra tiempo al principio de un análisis?
17.11.5 Ejercicio 5. La errata que no avisa
Crea pais_df <- as.data.frame(paises) y pais_tb <- as_tibble(paises). En los
dos, pide la columna con el nombre incompleto: $pib en vez de
$pib_per_capita.
Verificación: una de las dos devuelve datos y la otra devuelve NULL con
una advertencia.
En palabras: imagina que esa línea está en el medio de un análisis de 200 líneas. ¿Cuál de los dos comportamientos prefieres y por qué? Este es el argumento más fuerte del capítulo a favor del tibble: escríbelo con tus palabras.
17.11.6 Ejercicio 6. $, [[ y [ no dan lo mismo
Con pais_tb y pais_df del ejercicio anterior, saca la columna
esperanza_de_vida de cuatro maneras: con $, con [["..."]], con
["..."] (un solo corchete) y con [, "..."]. Usa class() en cada resultado.
Verificación: dos de las cuatro devuelven un vector y las otras dos una
tabla, y [, "..."] no se comporta igual en el data frame que en el tibble.
En palabras: ¿cuál de las cuatro usarías dentro de una función que recibe el
nombre de la columna como texto? ¿Por qué esa diferencia de [, "..."] puede
romper un script viejo?
17.11.7 Ejercicio 7 (BONO). Los nombres de fila se pierden
mtcars guarda los modelos de carro en los nombres de fila, no en una
columna. Míralos con rownames(mtcars), conviértelo con as_tibble() y vuelve a
mirar. Después hazlo bien con tibble::rownames_to_column().
Verificación: el tibble hecho con as_tibble() tiene 11 columnas y ya no
sabes qué carro es cada fila; el hecho con rownames_to_column() tiene 12.
En palabras: ¿por qué el tibble decidió no guardar nombres de fila? Piensa en qué son realmente esos nombres y en dónde deberían estar según lo que aprendiste sobre datos ordenados.