3  Uso de dplyr

En el capítulo anterior trabajamos las opciones básicas de ggplot para construir gráficas y explorar los datos.1 Esta exploración requiere de unos datos organizados y en este curso trabajaremos con bases de datos estructuradas en formato tidy, donde cada columna es una variable y cada fila es una observación.

1 En realidad, nos preocupamos más del cómo hacer las gráficas que en el por qué y para qué, pero al final de este capítulo estaremos en capacidad de orientar nuestras habilidades para hacer un análisis apropiado de datos

Este capítulo lo vamos a dedicar a explorar las opciones y funcionalidades de dplyr, un paquete que hace parte del tidyverse y que nos va a ayudar a realizar tareas como: transformar variables, reordenar, filtrar, agrupar, crear nuevas variables, renombrar, hacer resúmenes, etc. Al igual que en la construcción de gráficas, hay varias formas de llevar a cabo este tipo de tareas en R pero seguiremos fieles a la filosofía de elegir una de esas herramientas y procurar adquirir rápidamente la fluidez necesaria para aplicarla en el análisis de datos.

Las operaciones de dplyr las podemos clasificar según la forma en que se aplican en la base de datos, distinguiremos los siguientes casos:

  1. Operaciones por filas
  2. Operaciones por columnas
  3. Operaciones por grupos

De forma similar a ggplot, dplyr funciona en forma gramática, lo que significa que escribir y leer el código es más intuitivo, las operaciones se interpretan de izquierda a derecha en lugar de hacerlo de forma anidada en funciones, así que haremos uso extensivo del operador pipe. A diferencia de ggplot, donde solo se usaba este operador para aplicar la función ggplot a una base de datos y luego se agregaban capas con el signo +, en dplyr solo usaremos el operador pipe. dplyr opera sobre bases de datos y devuelve como resultado, bases de datos.

Usaremos la base de datos diamonds, instalada con ggplot2, que contiene 53.940 observaciones y 10 variables. Como siempre, lo mínimo es conocer las variables y unidades en el conjunto de datos, podemos ejecutar ?diamonds o buscar en internet la información necesaria

library(tidyverse)
diamonds
# A tibble: 53,940 × 10
   carat cut       color clarity depth table price     x     y     z
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1  0.23 Ideal     E     SI2      61.5    55   326  3.95  3.98  2.43
 2  0.21 Premium   E     SI1      59.8    61   326  3.89  3.84  2.31
 3  0.23 Good      E     VS1      56.9    65   327  4.05  4.07  2.31
 4  0.29 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63
 5  0.31 Good      J     SI2      63.3    58   335  4.34  4.35  2.75
 6  0.24 Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48
 7  0.24 Very Good I     VVS1     62.3    57   336  3.95  3.98  2.47
 8  0.26 Very Good H     SI1      61.9    55   337  4.07  4.11  2.53
 9  0.22 Fair      E     VS2      65.1    61   337  3.87  3.78  2.49
10  0.23 Very Good H     VS1      59.4    61   338  4     4.05  2.39
# ℹ 53,930 more rows
glimpse(diamonds) # ¿cuál es la diferencia?
Rows: 53,940
Columns: 10
$ carat   <dbl> 0.23, 0.21, 0.23, 0.29, 0.31, 0.24, 0.24, 0.26, 0.22, 0.23, 0.…
$ cut     <ord> Ideal, Premium, Good, Premium, Good, Very Good, Very Good, Ver…
$ color   <ord> E, E, E, I, J, J, I, H, E, H, J, J, F, J, E, E, I, J, J, J, I,…
$ clarity <ord> SI2, SI1, VS1, VS2, SI2, VVS2, VVS1, SI1, VS2, VS1, SI1, VS1, …
$ depth   <dbl> 61.5, 59.8, 56.9, 62.4, 63.3, 62.8, 62.3, 61.9, 65.1, 59.4, 64…
$ table   <dbl> 55, 61, 65, 58, 58, 57, 57, 55, 61, 61, 55, 56, 61, 54, 62, 58…
$ price   <int> 326, 326, 327, 334, 335, 336, 336, 337, 337, 338, 339, 340, 34…
$ x       <dbl> 3.95, 3.89, 4.05, 4.20, 4.34, 3.94, 3.95, 4.07, 3.87, 4.00, 4.…
$ y       <dbl> 3.98, 3.84, 4.07, 4.23, 4.35, 3.96, 3.98, 4.11, 3.78, 4.05, 4.…
$ z       <dbl> 2.43, 2.31, 2.31, 2.63, 2.75, 2.48, 2.47, 2.53, 2.49, 2.39, 2.…

Realice algunas gráficas para explorar relaciones básicas entre algunas de las variables

diamonds |> ggplot(aes(x = carat, y = price, color = cut)) +
  geom_point() +
  facet_wrap(facets = ~cut)

diamonds |> ggplot(aes(x = cut, y = price, fill = cut)) +
  geom_boxplot()

diamonds |> ggplot(aes(x = color, y = price, fill = color)) +
  geom_boxplot()

library(ggridges)
diamonds |> ggplot(aes(x = price, y = clarity, fill = clarity)) +
  geom_density_ridges2()

3.1 Operaciones sobre filas

Nada que agregar, son operaciones o funciones que modifican de alguna forma las filas u observaciones en la base de datos. Dentro de estas funciones tenemos operaciones como filtrar y ordenar. Las funciones principales en este grupo son:

  • arrange(): Ordena las filas de forma ascendente o descendente para valores de una o más variables
  • filter(): Selecciona o filtra los datos que cumplen una o más condiciones
  • distinct(): Selecciona valores únicos

Podemos ordenar las filas en diamonds en orden ascendente o descendente según el precio, o cualquier otra variable numérica

diamonds |> arrange(price)
# A tibble: 53,940 × 10
   carat cut       color clarity depth table price     x     y     z
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1  0.23 Ideal     E     SI2      61.5    55   326  3.95  3.98  2.43
 2  0.21 Premium   E     SI1      59.8    61   326  3.89  3.84  2.31
 3  0.23 Good      E     VS1      56.9    65   327  4.05  4.07  2.31
 4  0.29 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63
 5  0.31 Good      J     SI2      63.3    58   335  4.34  4.35  2.75
 6  0.24 Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48
 7  0.24 Very Good I     VVS1     62.3    57   336  3.95  3.98  2.47
 8  0.26 Very Good H     SI1      61.9    55   337  4.07  4.11  2.53
 9  0.22 Fair      E     VS2      65.1    61   337  3.87  3.78  2.49
10  0.23 Very Good H     VS1      59.4    61   338  4     4.05  2.39
# ℹ 53,930 more rows
diamonds |> arrange(desc(price))
# A tibble: 53,940 × 10
   carat cut       color clarity depth table price     x     y     z
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1  2.29 Premium   I     VS2      60.8    60 18823  8.5   8.47  5.16
 2  2    Very Good G     SI1      63.5    56 18818  7.9   7.97  5.04
 3  1.51 Ideal     G     IF       61.7    55 18806  7.37  7.41  4.56
 4  2.07 Ideal     G     SI2      62.5    55 18804  8.2   8.13  5.11
 5  2    Very Good H     SI1      62.8    57 18803  7.95  8     5.01
 6  2.29 Premium   I     SI1      61.8    59 18797  8.52  8.45  5.24
 7  2.04 Premium   H     SI1      58.1    60 18795  8.37  8.28  4.84
 8  2    Premium   I     VS1      60.8    59 18795  8.13  8.02  4.91
 9  1.71 Premium   F     VS2      62.3    59 18791  7.57  7.53  4.7 
10  2.15 Ideal     G     SI2      62.6    54 18791  8.29  8.35  5.21
# ℹ 53,930 more rows

Si queremos ver los valores únicos de las variables que son categóricas2 (cut, color y clarity) podemos usar distinct(cat1) o combinaciones únicas de varias de ellas con distinct(fact1, fact2)

2 No tiene mucho sentido hacerlo para variables continuas

diamonds |> distinct(cut)
# A tibble: 5 × 1
  cut      
  <ord>    
1 Ideal    
2 Premium  
3 Good     
4 Very Good
5 Fair     
diamonds |> distinct(color, clarity) |> arrange(color, desc(clarity))
# A tibble: 56 × 2
   color clarity
   <ord> <ord>  
 1 D     IF     
 2 D     VVS1   
 3 D     VVS2   
 4 D     VS1    
 5 D     VS2    
 6 D     SI1    
 7 D     SI2    
 8 D     I1     
 9 E     IF     
10 E     VVS1   
# ℹ 46 more rows

Note que en el último código, luego de captar las combinaciones únicas de color y clarity, se ordenan los datos de forma ascendente para color y para valores repetidos de color se ordenan de forma descendente para clarity.

La base de datos diamonds es un tibble. Un tibble es un data.frame pero con algunas características especiales. Su principal diferencia con un data.frame es que al momento de imprimir la base de datos, no se imprimen todos los datos sino solo las primeras 10 observaciones, algo bastante bueno si se está trabajando con bases de datos con muchas observaciones. Si deseamos imprimir todas las observaciones o una cantidad determinada de ellas, debemos solicitarlo3

3 Omitimos la salida para facilitar la lectura del documento

print(diamonds, n = 20)
diamonds |> distinct(color, clarity) |> 
  arrange(color, desc(clarity)) |> print(n = 56) # todas (mejórelo)

Siempre que aplicamos distinct(), la base de datos resultante, no tendrá todas las variables originales, solo mantendrá aquellas involucradas en la operación (¿por qué eso puede ser deseable?)

Hay una forma de mantener todas las variables, con el argumento y valor .keep_all = TRUE (¿por qué es necesario poner un punto al inicio?). En este caso, se mantendrá la primera coincidencia para cada combinaicón única encontrada.

diamonds |> distinct(clarity, color, .keep_all = TRUE)
# A tibble: 56 × 10
   carat cut       color clarity depth table price     x     y     z
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1  0.23 Ideal     E     SI2      61.5    55   326  3.95  3.98  2.43
 2  0.21 Premium   E     SI1      59.8    61   326  3.89  3.84  2.31
 3  0.23 Good      E     VS1      56.9    65   327  4.05  4.07  2.31
 4  0.29 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63
 5  0.31 Good      J     SI2      63.3    58   335  4.34  4.35  2.75
 6  0.24 Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48
 7  0.24 Very Good I     VVS1     62.3    57   336  3.95  3.98  2.47
 8  0.26 Very Good H     SI1      61.9    55   337  4.07  4.11  2.53
 9  0.22 Fair      E     VS2      65.1    61   337  3.87  3.78  2.49
10  0.23 Very Good H     VS1      59.4    61   338  4     4.05  2.39
# ℹ 46 more rows

filter() es quizás, la función más usada en filas. Nos permite seleccionar un subconjunto de los datos que cumplen uno o más criterios. La función requiere una base de datos como primer argumento y luego una serie de condiciones sobre los valores de una o más variables. Estas condiciones deben devolver un vector de valores lógicos que indicarán las filas a seleccionar.

Es buen momento para recordar algunas operaciones con valores lógicos en R. Los valores lógicos son TRUE y FALSE o T y F. Podemos obtener estos valores al comparar con: >, >=, <, <=, ==, !=

2 == 5 # FALSE
[1] FALSE
3 >= 0 # TRUE
[1] TRUE
2 < -3 # FALSE
[1] FALSE
3 != 6 # TRUE
[1] TRUE

El operador “o” es |, el operador “y” es &, el

(2 > 0) & (10 > 20) # TRUE y FALSE es FALSE
[1] FALSE
(2 > 0) | (10 > 20) # TRUE o FALSE es TRUE
[1] TRUE

Claramente, estas operaciones se pueden aplicar sobre vectores

c(2,6,9,3) >= 5
[1] FALSE  TRUE  TRUE FALSE
(c(7, 2, 9, 3, 1) < 4) & (c(1, 2, 8, 2, 0))
[1] FALSE  TRUE FALSE  TRUE FALSE

Como se mencionó, el primer argumento en dplyr es una base de datos, y podemos pensar lo siguiente como un vector de valores lógicos donde se debe tener un valor de TRUE en cada posición que se quiera filtrar o extraer. Para entender con claridad el funcionamiento de filter(), vamos a crear una pequeña base de datos

set.seed(123)
data_prueba <- tibble(
  var1 = sample(c("a", "b", "c"), 10, replace = T),
  var2 = runif(10, 3, 7),
  var3 = runif(10)
)
data_prueba
# A tibble: 10 × 3
   var1   var2  var3
   <chr> <dbl> <dbl>
 1 c      6.83 0.890
 2 c      4.81 0.693
 3 c      5.71 0.641
 4 b      5.29 0.994
 5 c      3.41 0.656
 6 b      6.60 0.709
 7 b      3.98 0.544
 8 b      3.17 0.594
 9 c      4.31 0.289
10 a      6.82 0.147

Supongamos que, de estas 10 filas, queremos seleccionar o filtrar la fila 1 y 4.

data_prueba |> filter(c(T,F,F,T,F,F,F,F,F,F))
# A tibble: 2 × 3
  var1   var2  var3
  <chr> <dbl> <dbl>
1 c      6.83 0.890
2 b      5.29 0.994

Esta es la forma en que opera filter(), aunque el vector de valores lógicos será resultado de algunas condiciones sobre los valores de las variables. Supongamos que queremos filtrar aquellos datos o filas en los que el valor de var3 es mayor a 0.7, lo que debemos escribir es

data_prueba |> filter(var3 > 0.7)
# A tibble: 3 × 3
  var1   var2  var3
  <chr> <dbl> <dbl>
1 c      6.83 0.890
2 b      5.29 0.994
3 b      6.60 0.709

Podemos usar tantas combinaciones o condiciones como se requieran sobre las variables. En el siguiente ejemplo, filtramos los datos para los que var1 tiene el valor “c” y var3 es menor que 0.65

data_prueba |> filter(var1 == "c" & var3 < 0.65)
# A tibble: 2 × 3
  var1   var2  var3
  <chr> <dbl> <dbl>
1 c      5.71 0.641
2 c      4.31 0.289

Volvamos a trabajar con diamonds, para recordar sus variables volvamos a imprimir los nombres de las columnas

glimpse(diamonds)
Rows: 53,940
Columns: 10
$ carat   <dbl> 0.23, 0.21, 0.23, 0.29, 0.31, 0.24, 0.24, 0.26, 0.22, 0.23, 0.…
$ cut     <ord> Ideal, Premium, Good, Premium, Good, Very Good, Very Good, Ver…
$ color   <ord> E, E, E, I, J, J, I, H, E, H, J, J, F, J, E, E, I, J, J, J, I,…
$ clarity <ord> SI2, SI1, VS1, VS2, SI2, VVS2, VVS1, SI1, VS2, VS1, SI1, VS1, …
$ depth   <dbl> 61.5, 59.8, 56.9, 62.4, 63.3, 62.8, 62.3, 61.9, 65.1, 59.4, 64…
$ table   <dbl> 55, 61, 65, 58, 58, 57, 57, 55, 61, 61, 55, 56, 61, 54, 62, 58…
$ price   <int> 326, 326, 327, 334, 335, 336, 336, 337, 337, 338, 339, 340, 34…
$ x       <dbl> 3.95, 3.89, 4.05, 4.20, 4.34, 3.94, 3.95, 4.07, 3.87, 4.00, 4.…
$ y       <dbl> 3.98, 3.84, 4.07, 4.23, 4.35, 3.96, 3.98, 4.11, 3.78, 4.05, 4.…
$ z       <dbl> 2.43, 2.31, 2.31, 2.63, 2.75, 2.48, 2.47, 2.53, 2.49, 2.39, 2.…

Queremos filtrar los datos para los diamantes que tienen las mejores cualidades en términos de cut (“Ideal”), color (“D”) y clarity (“IF”)

diamonds |> 
  filter(cut == "Ideal" & color == "D" & clarity == "IF")
# A tibble: 28 × 10
   carat cut   color clarity depth table price     x     y     z
   <dbl> <ord> <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1  0.51 Ideal D     IF       62      56  3446  5.14  5.18  3.2 
 2  0.51 Ideal D     IF       62.1    55  3446  5.12  5.13  3.19
 3  0.53 Ideal D     IF       61.5    54  3517  5.27  5.21  3.22
 4  0.53 Ideal D     IF       62.2    55  3812  5.17  5.19  3.22
 5  0.63 Ideal D     IF       61.2    53  3832  5.55  5.6   3.41
 6  0.59 Ideal D     IF       60.7    58  4161  5.45  5.49  3.32
 7  0.59 Ideal D     IF       60.9    57  4208  5.4   5.43  3.3 
 8  0.56 Ideal D     IF       62.4    56  4216  5.24  5.28  3.28
 9  0.56 Ideal D     IF       61.9    57  4293  5.28  5.31  3.28
10  0.56 Ideal D     IF       60.8    58  4632  5.35  5.31  3.24
# ℹ 18 more rows

Seleccionamos los diamantes más baratos y más caros (1%), y los ordenamos de forma descendente según su precio

x_inf <- quantile(diamonds$price, probs = 0.01)
x_sup <- quantile(diamonds$price, probs = 0.99)
diamonds |> 
  filter(price < x_inf | price > x_sup) |> 
  arrange(desc(price))
# A tibble: 1,069 × 10
   carat cut       color clarity depth table price     x     y     z
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1  2.29 Premium   I     VS2      60.8    60 18823  8.5   8.47  5.16
 2  2    Very Good G     SI1      63.5    56 18818  7.9   7.97  5.04
 3  1.51 Ideal     G     IF       61.7    55 18806  7.37  7.41  4.56
 4  2.07 Ideal     G     SI2      62.5    55 18804  8.2   8.13  5.11
 5  2    Very Good H     SI1      62.8    57 18803  7.95  8     5.01
 6  2.29 Premium   I     SI1      61.8    59 18797  8.52  8.45  5.24
 7  2.04 Premium   H     SI1      58.1    60 18795  8.37  8.28  4.84
 8  2    Premium   I     VS1      60.8    59 18795  8.13  8.02  4.91
 9  1.71 Premium   F     VS2      62.3    59 18791  7.57  7.53  4.7 
10  2.15 Ideal     G     SI2      62.6    54 18791  8.29  8.35  5.21
# ℹ 1,059 more rows

Al pasar las condiciones con las que queremos filtrar los datos, el operador & puede ser reemplazado por una , o dicho de otra forma, las condiciones separadas por , se interpretarán como &.

Si queremos seleccionar los diamantes que tienen el atributo clarity más pobre (los 3 peores): “I1”, “SI2”, “SI1”

diamonds |> 
  filter(clarity == "I1" | clarity == "SI2" | clarity == "SI1")
# A tibble: 23,000 × 10
   carat cut       color clarity depth table price     x     y     z
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1  0.23 Ideal     E     SI2      61.5    55   326  3.95  3.98  2.43
 2  0.21 Premium   E     SI1      59.8    61   326  3.89  3.84  2.31
 3  0.31 Good      J     SI2      63.3    58   335  4.34  4.35  2.75
 4  0.26 Very Good H     SI1      61.9    55   337  4.07  4.11  2.53
 5  0.3  Good      J     SI1      64      55   339  4.25  4.28  2.73
 6  0.22 Premium   F     SI1      60.4    61   342  3.88  3.84  2.33
 7  0.31 Ideal     J     SI2      62.2    54   344  4.35  4.37  2.71
 8  0.2  Premium   E     SI2      60.2    62   345  3.79  3.75  2.27
 9  0.32 Premium   E     I1       60.9    58   345  4.38  4.42  2.68
10  0.3  Ideal     I     SI2      62      54   348  4.31  4.34  2.68
# ℹ 22,990 more rows

Cuando estamos evaluando la condición de que una variable tome alguno entre 2 o más valores, es más sencillo usar var %in% c(valor1, ..., valorn) en lugar de var == valor1 | var == "valor2" | ... var == "valorn". El siguiente código hace la misma operación que el anterior

diamonds |> filter(clarity %in% c("I1", "SI2", "SI1", "VS2"))
# A tibble: 35,258 × 10
   carat cut       color clarity depth table price     x     y     z
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1  0.23 Ideal     E     SI2      61.5    55   326  3.95  3.98  2.43
 2  0.21 Premium   E     SI1      59.8    61   326  3.89  3.84  2.31
 3  0.29 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63
 4  0.31 Good      J     SI2      63.3    58   335  4.34  4.35  2.75
 5  0.26 Very Good H     SI1      61.9    55   337  4.07  4.11  2.53
 6  0.22 Fair      E     VS2      65.1    61   337  3.87  3.78  2.49
 7  0.3  Good      J     SI1      64      55   339  4.25  4.28  2.73
 8  0.22 Premium   F     SI1      60.4    61   342  3.88  3.84  2.33
 9  0.31 Ideal     J     SI2      62.2    54   344  4.35  4.37  2.71
10  0.2  Premium   E     SI2      60.2    62   345  3.79  3.75  2.27
# ℹ 35,248 more rows

3.2 Operaciones sobre columnas

Para agregar nuevas variables a la base de datos se usa mutate(), estas pueden ser variables externas o creadas en el momento o resultado de cálculo de variables dentro de la base de datos misma4

4 esto es algo bastante bueno, normalmente no podríamos hacerlo ya que las variables en la base de datos no están guardadas directamente en el entorno de variables de la sesión de trabajo

var_inventada <- sample(c("c1", "c2", "c3"), size = nrow(diamonds), replace = T)
diamonds |> 
  mutate(
    var_nueva = var_inventada, # una variable externa
    var_nueva2 = runif(nrow(diamonds)), # una creada en el momento
    var_nueva3 = x + y + y # una con las variables existentes en la base de datos
  ) |> glimpse()
Rows: 53,940
Columns: 13
$ carat      <dbl> 0.23, 0.21, 0.23, 0.29, 0.31, 0.24, 0.24, 0.26, 0.22, 0.23,…
$ cut        <ord> Ideal, Premium, Good, Premium, Good, Very Good, Very Good, …
$ color      <ord> E, E, E, I, J, J, I, H, E, H, J, J, F, J, E, E, I, J, J, J,…
$ clarity    <ord> SI2, SI1, VS1, VS2, SI2, VVS2, VVS1, SI1, VS2, VS1, SI1, VS…
$ depth      <dbl> 61.5, 59.8, 56.9, 62.4, 63.3, 62.8, 62.3, 61.9, 65.1, 59.4,…
$ table      <dbl> 55, 61, 65, 58, 58, 57, 57, 55, 61, 61, 55, 56, 61, 54, 62,…
$ price      <int> 326, 326, 327, 334, 335, 336, 336, 337, 337, 338, 339, 340,…
$ x          <dbl> 3.95, 3.89, 4.05, 4.20, 4.34, 3.94, 3.95, 4.07, 3.87, 4.00,…
$ y          <dbl> 3.98, 3.84, 4.07, 4.23, 4.35, 3.96, 3.98, 4.11, 3.78, 4.05,…
$ z          <dbl> 2.43, 2.31, 2.31, 2.63, 2.75, 2.48, 2.47, 2.53, 2.49, 2.39,…
$ var_nueva  <chr> "c1", "c2", "c3", "c2", "c1", "c3", "c3", "c1", "c3", "c2",…
$ var_nueva2 <dbl> 0.50870149, 0.09304586, 0.52525136, 0.24570402, 0.92814596,…
$ var_nueva3 <dbl> 11.91, 11.57, 12.19, 12.66, 13.04, 11.86, 11.91, 12.29, 11.…

Por defecto, las variables creadas serán agregadas “a la derecha” de la base de datos. Esto se puede controlar con:

  • .before: El valor debe ser un número entero o nombre de variable, las nuevas variables se colocarán antes de ese número de columna o variable
  • .after: 🧠

También es posible especificar las variables que se quieren mantener con el argumento .keep, las opciones son: all (por defecto), used (solo las usadas), unused, none

diamonds |> 
  mutate(
    var_nueva = var_inventada,
    var_nueva2 = runif(nrow(diamonds)),
    var_nueva3 = x + y + z,
    .keep = "used",
    .after = x
  )
# A tibble: 53,940 × 6
       x var_nueva var_nueva2 var_nueva3     y     z
   <dbl> <chr>          <dbl>      <dbl> <dbl> <dbl>
 1  3.95 c1            0.0301       10.4  3.98  2.43
 2  3.89 c2            0.343        10.0  3.84  2.31
 3  4.05 c3            0.561        10.4  4.07  2.31
 4  4.2  c2            0.620        11.1  4.23  2.63
 5  4.34 c1            0.0352       11.4  4.35  2.75
 6  3.94 c3            0.170        10.4  3.96  2.48
 7  3.95 c3            0.864        10.4  3.98  2.47
 8  4.07 c1            0.469        10.7  4.11  2.53
 9  3.87 c3            0.738        10.1  3.78  2.49
10  4    c2            0.217        10.4  4.05  2.39
# ℹ 53,930 more rows

Es posible renombrar las variables con rename()

diamonds |> 
  rename(
    precio = price,
    peso = carat,
    corte = cut, 
    claridad = clarity
  )
# A tibble: 53,940 × 10
    peso corte     color claridad depth table precio     x     y     z
   <dbl> <ord>     <ord> <ord>    <dbl> <dbl>  <int> <dbl> <dbl> <dbl>
 1  0.23 Ideal     E     SI2       61.5    55    326  3.95  3.98  2.43
 2  0.21 Premium   E     SI1       59.8    61    326  3.89  3.84  2.31
 3  0.23 Good      E     VS1       56.9    65    327  4.05  4.07  2.31
 4  0.29 Premium   I     VS2       62.4    58    334  4.2   4.23  2.63
 5  0.31 Good      J     SI2       63.3    58    335  4.34  4.35  2.75
 6  0.24 Very Good J     VVS2      62.8    57    336  3.94  3.96  2.48
 7  0.24 Very Good I     VVS1      62.3    57    336  3.95  3.98  2.47
 8  0.26 Very Good H     SI1       61.9    55    337  4.07  4.11  2.53
 9  0.22 Fair      E     VS2       65.1    61    337  3.87  3.78  2.49
10  0.23 Very Good H     VS1       59.4    61    338  4     4.05  2.39
# ℹ 53,930 more rows

Podemos seleccionar un subconjunto de variables con select()