Crear variables nuevas con dplyr::mutate()

11/12/2025

dplyr básico

En esta ocasión veremos la función que nos permite crear variables nuevas, a partir de los aprendizajes sobre manipulación de datos que vimos en tutoriales anteriores.

Para crear variables nuevas, o transformar variables existentes, usaremos la función mutate(), que forma parte del paquete {dplyr}.

Esquema de la creación de una columna a partir de dos columnas existentes: la tercera columna es la suma de las dos anteriores

La función mutate() nos va a permitir crear nuevas variables, ya sea usando datos nuevos, alguna función que genera datos, modificando los datos de una columna existente, o realizando un cálculo a partir de una o más columnas de la tabla.

Introducción

Vamos a empezar con ejemplos básicos y luego pasaremos a datos reales.

Lo primero que haremos será cargar el paquete {dplyr}:

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

Crear nuevas columnas

Empezaremos con una tabla de datos de ejemplo, llamada creativamente ejemplo:

library(dplyr)

ejemplo <- tibble(números = 1:3)

ejemplo
# A tibble: 3 × 1
  números
    <int>
1       1
2       2
3       3

Podemos usar mutate() para crear una nueva variable o columna (¡son sinónimos! 🤓).

Para crear usar mutate(), aplicamos esta función a un data frame conectando los datos a la función con un conector (|> o %>%).

ejemplo |> 
  mutate(prueba = 1)
# A tibble: 3 × 2
  números prueba
    <int>  <dbl>
1       1      1
2       2      1
3       3      1

Creamos una nueva columna llamada prueba, que contiene el valor 1. Como le dimos un sólo valor (1), el valor se repite en todas las filas.

¿Qué hicimos?

Para crear la variable prueba, dentro de mutate():

  1. Primero pusimos el nombre de la columna que queríamos crear (prueba),
  2. Luego un signo igual (=), que indica que ésto va a ser aquello,
  3. Finalmente el valor que queremos que contenga la nueva columna ( 1).

Creemos otra columna, llamada saludo:

ejemplo |> 
  mutate(saludo = "hola")
# A tibble: 3 × 2
  números saludo
    <int> <chr> 
1       1 hola  
2       2 hola  
3       3 hola  

De esta forma podemos crear variables que contengan un único valor.

También podemos usar funciones para crear los valores que va a tener una columna. Por ejemplo, creemos una columna llamada azar que contenga números aleatorios entre 1 y 100:

ejemplo |> 
  mutate(azar = sample(1:100, size =  3))
# A tibble: 3 × 2
  números  azar
    <int> <int>
1       1    91
2       2     7
3       3    51

En este ejemplo, los valores de la columna son definidos por la función que usamos.

Modificar variables existentes

También podemos usar mutate() para modificar columnas que ya existen en el data frame. Esto se hace simplemente poniendo en mutate() como nombre de la columna que vamos a crear el nombre de una columna existente que queremos modificar.

Por ejemplo, cambiemos los valores de números por unos distintos:

ejemplo |> 
  mutate(números = 4:6)
# A tibble: 3 × 1
  números
    <int>
1       4
2       5
3       6

En este caso, sobreescribimos la columna con datos nuevos.

Volvamos a ver los datos originales:

ejemplo
# A tibble: 3 × 1
  números
    <int>
1       1
2       2
3       3

En vez de cambiar completamente los datos de una columna, podemos editar una columna existente, usando los valores de la misma columna y ejecutando alguna operación sobre ellos, para obtener una versión editada de la misma columna:

ejemplo |> 
  mutate(números = números * 100)
# A tibble: 3 × 1
  números
    <dbl>
1     100
2     200
3     300

En este ejemplo, editamos la columna números, que contenía los valores 1, 2 y 3, declarando que números = números * 100; es decir, la columna va a ser igual a ella misma pero multiplicada por 100. Por eso ahora contiene los valores 100, 200 y 300, que son el resultado de multiplicar cada valor original por 100.

Crear una columna nueva en base a otra existente

Siguiendo el ejemplo anterior, podemos crear una nueva columna llamada doble que contenga el doble de los valores de la columna números:

ejemplo |> 
  mutate(doble = números * 2)
# A tibble: 3 × 2
  números doble
    <int> <dbl>
1       1     2
2       2     4
3       3     6

Así creamos una nueva columna basada en datos de una columna existente.

También podemos usar funciones para crear las variables nuevas:

ejemplo |> 
  mutate(doble = números * 2) |> 
  mutate(texto = paste(doble, "es el doble de", números))
# A tibble: 3 × 3
  números doble texto             
    <int> <dbl> <chr>             
1       1     2 2 es el doble de 1
2       2     4 4 es el doble de 2
3       3     6 6 es el doble de 3

Estas son las piezas básicas para trabajar con variables o columnas. ¡Ahora veámoslo con datos!


Ejemplo con datos

A continuación, usaremos datos sobre países de América Latina, que fueron obtenidos desde tablas de Wikipedia por medio de web scraping. Puedes revisar el script con el código del scraping aquí.

Ejecutaremos el siguiente código para obtener una tabla llamada datos en nuestro entorno de R:

datos <- tribble(
  ~pais,       ~pobreza, ~esperanza, ~escolaridad,
  "Chile",         5,    81.17,      11.29,
  "Uruguay",       6,    78.14,      10.54,
  "Argentina",    11,    77.69,      11.18,
  "Costa Rica",   13,    80.8,        8.84,
  "Panamá",       13,    79.59,      10.83,
  "Bolivia",      15,    68.58,      10.02,
  "Paraguay",     20,    73.84,       8.93,
  "México",       22,    75.07,       9.35,
  "Brasil",       24,    75.85,       8.43,
  "El Salvador",  28,    72.1,        7.3
)

La tabla datos contiene información sobre porcentaje de pobreza, esperanza de vida promedio y años de escolaridad promedio en varios países de América Latina.

Crear una variable nueva con mutate()

Usemos mutate() para crear una nueva columna llamada escolaridad_redondeada, que contenga los valores de la columna escolaridad redondeados al número entero más cercano:

datos |> 
  select(pais, escolaridad) |> 
  mutate(escolaridad_redondeada = round(escolaridad))
# A tibble: 10 × 3
   pais        escolaridad escolaridad_redondeada
   <chr>             <dbl>                  <dbl>
 1 Chile             11.3                      11
 2 Uruguay           10.5                      11
 3 Argentina         11.2                      11
 4 Costa Rica         8.84                      9
 5 Panamá            10.8                      11
 6 Bolivia           10.0                      10
 7 Paraguay           8.93                      9
 8 México             9.35                      9
 9 Brasil             8.43                      8
10 El Salvador        7.3                       7

En este caso aplicamos una función a una columna existente para obtener una columna nueva.

Crear una variable condicional con if_else()

Podemos usar mutate() junto con la función if_else() para crear una nueva columna basada en condiciones. Por ejemplo, creemos una columna llamada pobreza_nivel que indique si el porcentaje de pobreza alto (es mayor al 10%) o bajo:

datos |> 
  select(pais, pobreza) |> 
  mutate(pobreza_nivel = if_else(pobreza >= 10, "Alto", "Bajo"))
# A tibble: 10 × 3
   pais        pobreza pobreza_nivel
   <chr>         <dbl> <chr>        
 1 Chile             5 Bajo         
 2 Uruguay           6 Bajo         
 3 Argentina        11 Alto         
 4 Costa Rica       13 Alto         
 5 Panamá           13 Alto         
 6 Bolivia          15 Alto         
 7 Paraguay         20 Alto         
 8 México           22 Alto         
 9 Brasil           24 Alto         
10 El Salvador      28 Alto         

Crear una variable con múltiples condiciones usando case_when()

Podemos usar mutate() junto con la función case_when() para crear una nueva columna basada en múltiples condiciones. Por ejemplo, creemos una columna llamada esperanza_nivel que clasifique la esperanza de vida en “Alta”, “Media” y “Baja”:

datos |> 
  select(pais, esperanza) |> 
  mutate(esperanza_nivel = case_when(
    esperanza >= 80 ~ "Alta",
    esperanza >= 70 ~ "Media",
    esperanza <  70 ~ "Baja"
  ))
# A tibble: 10 × 3
   pais        esperanza esperanza_nivel
   <chr>           <dbl> <chr>          
 1 Chile            81.2 Alta           
 2 Uruguay          78.1 Media          
 3 Argentina        77.7 Media          
 4 Costa Rica       80.8 Alta           
 5 Panamá           79.6 Media          
 6 Bolivia          68.6 Baja           
 7 Paraguay         73.8 Media          
 8 México           75.1 Media          
 9 Brasil           75.8 Media          
10 El Salvador      72.1 Media          

En el ejemplo anterior usamos números arbitrarios para recodificar una variable contínua en una variable categórica. En un caso real, deberíamos analizar la distribución de los datos para definir los puntos de corte adecuados. Una forma muy rudimentaria de hacer ésto es usando desviaciones estándar:

datos |> 
  mutate(esperanza_nivel = case_when(
    esperanza >= mean(esperanza) + sd(esperanza) ~ "Alta",
    esperanza <= mean(esperanza) - sd(esperanza) ~ "Baja",
    TRUE ~ "Media"
  ))
# A tibble: 10 × 5
   pais        pobreza esperanza escolaridad esperanza_nivel
   <chr>         <dbl>     <dbl>       <dbl> <chr>          
 1 Chile             5      81.2       11.3  Alta           
 2 Uruguay           6      78.1       10.5  Media          
 3 Argentina        11      77.7       11.2  Media          
 4 Costa Rica       13      80.8        8.84 Alta           
 5 Panamá           13      79.6       10.8  Media          
 6 Bolivia          15      68.6       10.0  Baja           
 7 Paraguay         20      73.8        8.93 Media          
 8 México           22      75.1        9.35 Media          
 9 Brasil           24      75.8        8.43 Media          
10 El Salvador      28      72.1        7.3  Baja           

En este caso clasificamos la esperanza de vida en función de su distancia a la media, usando una desviación estándar como punto de corte: países que tengan valores que sean mayores al promedio más una desviación estándar serán altos, los que tengan valores menores al promedio menos una desviación estándar serán bajos, y el resto serán medios.

Calcular variables por grupos con group_by()

Podemos usar group_by() para crear variables nuevas basadas en grupos dentro de los datos; es decir, cuyo cálculo se haga dentro de cada grupo definido.

Primero creemos un grupo:

datos_grupo <- datos |> 
  mutate(pobreza_nivel = if_else(pobreza >= 15, "Alto", "Bajo"))

datos_grupo
# A tibble: 10 × 5
   pais        pobreza esperanza escolaridad pobreza_nivel
   <chr>         <dbl>     <dbl>       <dbl> <chr>        
 1 Chile             5      81.2       11.3  Bajo         
 2 Uruguay           6      78.1       10.5  Bajo         
 3 Argentina        11      77.7       11.2  Bajo         
 4 Costa Rica       13      80.8        8.84 Bajo         
 5 Panamá           13      79.6       10.8  Bajo         
 6 Bolivia          15      68.6       10.0  Alto         
 7 Paraguay         20      73.8        8.93 Alto         
 8 México           22      75.1        9.35 Alto         
 9 Brasil           24      75.8        8.43 Alto         
10 El Salvador      28      72.1        7.3  Alto         

Ahora calculemos el promedio de esperanza de vida dentro de cada grupo de pobreza usando group_by() y mutate():

datos_grupo |> 
  select(pais, pobreza_nivel, esperanza) |> 
  group_by(pobreza_nivel) |> 
  mutate(esperanza_promedio = mean(esperanza)) |> 
  mutate(esperanza_diferencia = esperanza - esperanza_promedio)
# A tibble: 10 × 5
# Groups:   pobreza_nivel [2]
   pais        pobreza_nivel esperanza esperanza_promedio esperanza_diferencia
   <chr>       <chr>             <dbl>              <dbl>                <dbl>
 1 Chile       Bajo               81.2               79.5                1.69 
 2 Uruguay     Bajo               78.1               79.5               -1.34 
 3 Argentina   Bajo               77.7               79.5               -1.79 
 4 Costa Rica  Bajo               80.8               79.5                1.32 
 5 Panamá      Bajo               79.6               79.5                0.112
 6 Bolivia     Alto               68.6               73.1               -4.51 
 7 Paraguay    Alto               73.8               73.1                0.752
 8 México      Alto               75.1               73.1                1.98 
 9 Brasil      Alto               75.8               73.1                2.76 
10 El Salvador Alto               72.1               73.1               -0.988

En este ejemplo, primero agrupamos los datos por la variable pobreza_nivel usando group_by(), y luego usamos mutate() para crear una nueva columna llamada esperanza_promedio, que contiene el promedio de esperanza de vida dentro de cada grupo. Finalmente, creamos otra columna llamada esperanza_diferencia, que contiene la diferencia entre la esperanza de vida individual y el promedio del grupo.

De este modo obtuvimos una nueva variable que muestra la diferencia de cada país respecto al promedio de su grupo; una especie de indicador.

Crear varias columnas al mismo tiempo con across()

Finalmente, podemos modificar o crear varias columnas nuevas al mismo tiempo usando mutate() junto con la función across(). Con across(), especificamos las variables que queremos afectar, y luego la fórmula que les vamos a aplicar.

Por ejemplo, podemos redondear todas las columnas al mismo tiempo:

datos |> 
  mutate(
    across(c(pobreza, esperanza, escolaridad), 
           ~round(.x)
    )
  )
# A tibble: 10 × 4
   pais        pobreza esperanza escolaridad
   <chr>         <dbl>     <dbl>       <dbl>
 1 Chile             5        81          11
 2 Uruguay           6        78          11
 3 Argentina        11        78          11
 4 Costa Rica       13        81           9
 5 Panamá           13        80          11
 6 Bolivia          15        69          10
 7 Paraguay         20        74           9
 8 México           22        75           9
 9 Brasil           24        76           8
10 El Salvador      28        72           7

La función que aplicamos se escribe con colita de chancho (~) para indicar que todas las variables especificadas van a ser afectadas por la misma función, representadas dentro de la función como .x 🐷

Incluso podemos hacerlo en menos código, al especificar que queremos afectar todas las columnas donde (where) sean numéricas (is.numeric):

datos |> 
  mutate(
    across(where(is.numeric), 
           ~round(.x)
    )
  )
# A tibble: 10 × 4
   pais        pobreza esperanza escolaridad
   <chr>         <dbl>     <dbl>       <dbl>
 1 Chile             5        81          11
 2 Uruguay           6        78          11
 3 Argentina        11        78          11
 4 Costa Rica       13        81           9
 5 Panamá           13        80          11
 6 Bolivia          15        69          10
 7 Paraguay         20        74           9
 8 México           22        75           9
 9 Brasil           24        76           8
10 El Salvador      28        72           7

Esto trae el beneficio de no tener que referirnos a las columnas por sus nombres!

Otro ejemplo sería aplicar una función que transforme todos los valores numéricos en texto, agregando una palabra antes del número:

datos |> 
  mutate(
    across(
      where(is.numeric), 
      ~paste("Valor:", .x)
    )
  )
# A tibble: 10 × 4
   pais        pobreza   esperanza    escolaridad 
   <chr>       <chr>     <chr>        <chr>       
 1 Chile       Valor: 5  Valor: 81.17 Valor: 11.29
 2 Uruguay     Valor: 6  Valor: 78.14 Valor: 10.54
 3 Argentina   Valor: 11 Valor: 77.69 Valor: 11.18
 4 Costa Rica  Valor: 13 Valor: 80.8  Valor: 8.84 
 5 Panamá      Valor: 13 Valor: 79.59 Valor: 10.83
 6 Bolivia     Valor: 15 Valor: 68.58 Valor: 10.02
 7 Paraguay    Valor: 20 Valor: 73.84 Valor: 8.93 
 8 México      Valor: 22 Valor: 75.07 Valor: 9.35 
 9 Brasil      Valor: 24 Valor: 75.85 Valor: 8.43 
10 El Salvador Valor: 28 Valor: 72.1  Valor: 7.3  

En este caso, el símbolo .x hace que el valor de cada observación se ponga en otro lugar de la función, en este caso al final de la función paste().

Podemos combinar mutate() con uno o varios mutate(across()) para crear o modificar varias columnas al mismo tiempo. Por ejemplo, podemos agregarle el signo de porcentaje a pobreza, luego redondear las columnas esperanza y escolaridad, y al final agregar un mismo texto a dos columnas:

datos |> 
  mutate(
    # redactar
    pobreza = paste(pobreza, "%", sep = ""),
    # redondear
    across(c(esperanza, escolaridad), ~round(.x, 0)),
    # redactar
    across(c(esperanza, escolaridad), ~paste(.x, "años"))
  )
# A tibble: 10 × 4
   pais        pobreza esperanza escolaridad
   <chr>       <chr>   <chr>     <chr>      
 1 Chile       5%      81 años   11 años    
 2 Uruguay     6%      78 años   11 años    
 3 Argentina   11%     78 años   11 años    
 4 Costa Rica  13%     81 años   9 años     
 5 Panamá      13%     80 años   11 años    
 6 Bolivia     15%     69 años   10 años    
 7 Paraguay    20%     74 años   9 años     
 8 México      22%     75 años   9 años     
 9 Brasil      24%     76 años   8 años     
10 El Salvador 28%     72 años   7 años     

En los casos de across() que hemos visto, las variable son editadas o modificadas, y por ende sobreescritas. Pero también podemos hacer que se creen variables nuevas! Pero, lógicamente, como estamos editando varias columnas a la vez, no podemos darles a todas un nombre distinto. En este caso, usamos el argumento .names dentro de across() para definir un patrón de nombres para las nuevas columnas:

datos |> 
  mutate(
    across(c(pobreza, esperanza, escolaridad), 
           ~round(.x),
           .names = "{.col}_redondeada"
    )
  )
# A tibble: 10 × 7
   pais    pobreza esperanza escolaridad pobreza_redondeada esperanza_redondeada
   <chr>     <dbl>     <dbl>       <dbl>              <dbl>                <dbl>
 1 Chile         5      81.2       11.3                   5                   81
 2 Uruguay       6      78.1       10.5                   6                   78
 3 Argent…      11      77.7       11.2                  11                   78
 4 Costa …      13      80.8        8.84                 13                   81
 5 Panamá       13      79.6       10.8                  13                   80
 6 Bolivia      15      68.6       10.0                  15                   69
 7 Paragu…      20      73.8        8.93                 20                   74
 8 México       22      75.1        9.35                 22                   75
 9 Brasil       24      75.8        8.43                 24                   76
10 El Sal…      28      72.1        7.3                  28                   72
# ℹ 1 more variable: escolaridad_redondeada <dbl>

En este caso, usamos {.col} dentro de .names para indicar que el nombre de la nueva columna va a ser igual al nombre de la columna original (representada por .col), seguido del texto _redondeada. Esta sintaxis para crear textos se llama glue y es muy útil para crear textos dinámicos en R.


Estas son las herramientas básicas que necesitas para crear y modificar variables en R! Al final se trata de usar mutate() para crear algo nuevo o editar algo existente, usando valores nuevos, otras columnas, o funciones, y combinar estas herramientas para llevar a cabo lo que necesitemos, ya sea limpieza de datos o análisis de datos más complejos.