class: center, middle .linea-superior[] .linea-inferior[] <img src="imagenes/logo_portada2.png" width="200" /> ## INE Educa: Clases abiertas de R ## Proyecto Ciencia de Datos ## Herramientas de edición de datos II --- name: diapo-basica background-image: url("imagenes/fondo2.PNG") background-size: contain; background-position: 100% 0% # Edición de datos II: lógica condicional --- template: diapo-basica Ahora sabemos cómo crear columnas y modificar columnas existentes. Sin embargo, las funciones que vimos se aplican de igual manera a toda la columna. -- A veces (***muchas*** veces), queremos aplicar **lógica condicional** a la creación o modificación de columnas. ¿Qué significa esto? -- .center[ <img src="imagenes/prueba_logica.png" width="600" />] --- template: diapo-basica ## if_else Esta función permite implementar la lógica anterior y tiene la siguiente sintaxis: ```r if_else(condicion_logica, valor_si_verdadero, valor_si_falso, valor_si_missing) ``` -- Esto podría leerse de la siguiente manera: evalúa la condición `condicion_logica` en cada fila, si esta se cumple en la fila, tomará el valor asignado en `valor_si_verdadero`, si no, toma el valor asignado en `valor_si_falso`. Por último, si la fila tenía un NA, nos permite especificar qué valor toma con `valor_si_missing`. -- Para aplicar esta función, volveremos a crear un dataset de prueba: ```r tabla_ejemplo <- data.frame(nombre = c('Claudio', 'Francisco', 'Francisca', 'Pedro'), edad = c(33, 44, 22, 31), estatura = c(171, 153, NA, 160)) ``` <table> <thead> <tr> <th style="text-align:left;"> nombre </th> <th style="text-align:right;"> edad </th> <th style="text-align:right;"> estatura </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> Claudio </td> <td style="text-align:right;"> 33 </td> <td style="text-align:right;"> 171 </td> </tr> <tr> <td style="text-align:left;"> Francisco </td> <td style="text-align:right;"> 44 </td> <td style="text-align:right;"> 153 </td> </tr> <tr> <td style="text-align:left;"> Francisca </td> <td style="text-align:right;"> 22 </td> <td style="text-align:right;"> NA </td> </tr> <tr> <td style="text-align:left;"> Pedro </td> <td style="text-align:right;"> 31 </td> <td style="text-align:right;"> 160 </td> </tr> </tbody> </table> --- template: diapo-basica ## if_else Marquemos en una nueva columna `mas_de_170` a las personas que miden más de 170cm y asignemos un valor especial `-66` para quienes tienen un valor nulo (`NA`). ```r tabla_ejemplo2 = tabla_ejemplo %>% mutate(mas_de_170 = if_else(condition = estatura > 170, true = 1, false = 0, missing = -66)) ``` <table> <thead> <tr> <th style="text-align:left;"> nombre </th> <th style="text-align:right;"> edad </th> <th style="text-align:right;"> estatura </th> <th style="text-align:right;"> mas_de_170 </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> Claudio </td> <td style="text-align:right;"> 33 </td> <td style="text-align:right;"> 171 </td> <td style="text-align:right;"> 1 </td> </tr> <tr> <td style="text-align:left;"> Francisco </td> <td style="text-align:right;"> 44 </td> <td style="text-align:right;"> 153 </td> <td style="text-align:right;"> 0 </td> </tr> <tr> <td style="text-align:left;"> Francisca </td> <td style="text-align:right;"> 22 </td> <td style="text-align:right;"> NA </td> <td style="text-align:right;"> -66 </td> </tr> <tr> <td style="text-align:left;"> Pedro </td> <td style="text-align:right;"> 31 </td> <td style="text-align:right;"> 160 </td> <td style="text-align:right;"> 0 </td> </tr> </tbody> </table> --- template: diapo-basica ## if_else Las expresiones `if_else` son bastante flexibles y aceptan expresiones como las de `mutate`, siempre y cuando **hagan referencia al mismo tipo de datos en todos los casos**. -- Un ejemplo ```r tabla_ejemplo3 = tabla_ejemplo %>% mutate(col_prueba = if_else(condition = edad > 35, true = edad * 2, false = (estatura - 100))) ``` -- <table> <thead> <tr> <th style="text-align:left;"> nombre </th> <th style="text-align:right;"> edad </th> <th style="text-align:right;"> estatura </th> <th style="text-align:right;"> col_prueba </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> Claudio </td> <td style="text-align:right;"> 33 </td> <td style="text-align:right;"> 171 </td> <td style="text-align:right;"> 71 </td> </tr> <tr> <td style="text-align:left;"> Francisco </td> <td style="text-align:right;"> 44 </td> <td style="text-align:right;"> 153 </td> <td style="text-align:right;"> 88 </td> </tr> <tr> <td style="text-align:left;"> Francisca </td> <td style="text-align:right;"> 22 </td> <td style="text-align:right;"> NA </td> <td style="text-align:right;"> NA </td> </tr> <tr> <td style="text-align:left;"> Pedro </td> <td style="text-align:right;"> 31 </td> <td style="text-align:right;"> 160 </td> <td style="text-align:right;"> 60 </td> </tr> </tbody> </table> --- template: diapo-basica ## if_else Las expresiones `if_else` son bastante flexibles y aceptan expresiones como las de `mutate`, siempre y cuando **hagan referencia al mismo tipo de datos en todos los casos (true, false, missing)**. -- Otro ejemplo: ```r tabla_ejemplo4 = tabla_ejemplo %>% mutate(empieza_con_F = if_else(condition = nombre %>% stringr::str_starts('F'), true = 'Sí', false = 'No')) ``` -- <table> <thead> <tr> <th style="text-align:left;"> nombre </th> <th style="text-align:right;"> edad </th> <th style="text-align:right;"> estatura </th> <th style="text-align:left;"> empieza_con_F </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> Claudio </td> <td style="text-align:right;"> 33 </td> <td style="text-align:right;"> 171 </td> <td style="text-align:left;"> No </td> </tr> <tr> <td style="text-align:left;"> Francisco </td> <td style="text-align:right;"> 44 </td> <td style="text-align:right;"> 153 </td> <td style="text-align:left;"> Sí </td> </tr> <tr> <td style="text-align:left;"> Francisca </td> <td style="text-align:right;"> 22 </td> <td style="text-align:right;"> NA </td> <td style="text-align:left;"> Sí </td> </tr> <tr> <td style="text-align:left;"> Pedro </td> <td style="text-align:right;"> 31 </td> <td style="text-align:right;"> 160 </td> <td style="text-align:left;"> No </td> </tr> </tbody> </table> --- template: diapo-basica ## case_when Cuando queremos generar una variable en base a más de una condición, la mejor alternativa es el uso de la función `case_when`. Esta función tiene una sintaxis ligeramente distinta: -- ```r case_when(condicion_logica1 ~ valor_si_condicion1, condicion_logica2 ~ valor_si_condicion2, condicion_logica3 ~ valor_si_condicion3, etc) ``` Puntos importantes a tener presente: -- Si no se cumple una condición, el valor asignado será `NA`. -- Las condiciones se evalúan en orden. Una vez se cumple una para una fila, se le asigna el valor correspondiente y el resto de condiciones dejan de evaluarse. --- template: diapo-basica ## case_when Veamos ejemplos que ilustren la función y los puntos anteriores. -- Creamos un dataframe de ejemplo: ```r regiones = data.frame(region = c(1:3, -99, NA), ingreso_promedio = c(8.5e5, 9e5, 9.5e5, 1e6, 1.5e6), ingreso_mediano = c(4.5e5, 6.5e5, 7e5, 8e5, 8.1e5)) %>% # Agregamos identificador de fila como primera columna: mutate(id_fila = row_number(), .before = region) ``` -- <table> <thead> <tr> <th style="text-align:right;"> id_fila </th> <th style="text-align:right;"> region </th> <th style="text-align:right;"> ingreso_promedio </th> <th style="text-align:right;"> ingreso_mediano </th> </tr> </thead> <tbody> <tr> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 850000 </td> <td style="text-align:right;"> 450000 </td> </tr> <tr> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 900000 </td> <td style="text-align:right;"> 650000 </td> </tr> <tr> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 950000 </td> <td style="text-align:right;"> 700000 </td> </tr> <tr> <td style="text-align:right;"> 4 </td> <td style="text-align:right;"> -99 </td> <td style="text-align:right;"> 1000000 </td> <td style="text-align:right;"> 800000 </td> </tr> <tr> <td style="text-align:right;"> 5 </td> <td style="text-align:right;"> NA </td> <td style="text-align:right;"> 1500000 </td> <td style="text-align:right;"> 810000 </td> </tr> </tbody> </table> --- template: diapo-basica ## case_when Recodifiquemos las regiones: -- ```r regiones_cod = regiones %>% mutate(region_cod = case_when(region == 1 ~ 'Arica y Parinacota', region == 2 ~ 'Antofagasta', region == 3 ~ 'Atacama')) ``` -- <table> <thead> <tr> <th style="text-align:right;"> id_fila </th> <th style="text-align:right;"> region </th> <th style="text-align:right;"> ingreso_promedio </th> <th style="text-align:right;"> ingreso_mediano </th> <th style="text-align:left;"> region_cod </th> </tr> </thead> <tbody> <tr> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 850000 </td> <td style="text-align:right;"> 450000 </td> <td style="text-align:left;"> Arica y Parinacota </td> </tr> <tr> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 900000 </td> <td style="text-align:right;"> 650000 </td> <td style="text-align:left;"> Antofagasta </td> </tr> <tr> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 950000 </td> <td style="text-align:right;"> 700000 </td> <td style="text-align:left;"> Atacama </td> </tr> <tr> <td style="text-align:right;"> 4 </td> <td style="text-align:right;"> -99 </td> <td style="text-align:right;"> 1000000 </td> <td style="text-align:right;"> 800000 </td> <td style="text-align:left;"> NA </td> </tr> <tr> <td style="text-align:right;"> 5 </td> <td style="text-align:right;"> NA </td> <td style="text-align:right;"> 1500000 </td> <td style="text-align:right;"> 810000 </td> <td style="text-align:left;"> NA </td> </tr> </tbody> </table> --- template: diapo-basica ## case_when Recodifiquemos las regiones: ```r regiones_cod = regiones %>% mutate(region_cod = case_when(region == 1 ~ 'Arica y Parinacota', region == 2 ~ 'Antofagasta', region == 3 ~ 'Atacama')) ``` <table class="table" style="margin-left: auto; margin-right: auto;"> <thead> <tr> <th style="text-align:right;"> id_fila </th> <th style="text-align:right;"> region </th> <th style="text-align:right;"> ingreso_promedio </th> <th style="text-align:right;"> ingreso_mediano </th> <th style="text-align:left;"> region_cod </th> </tr> </thead> <tbody> <tr> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 850000 </td> <td style="text-align:right;"> 450000 </td> <td style="text-align:left;"> <span style=" color: black !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: white !important;">Arica y Parinacota</span> </td> </tr> <tr> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 900000 </td> <td style="text-align:right;"> 650000 </td> <td style="text-align:left;"> <span style=" color: black !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: white !important;">Antofagasta</span> </td> </tr> <tr> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 950000 </td> <td style="text-align:right;"> 700000 </td> <td style="text-align:left;"> <span style=" color: black !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: white !important;">Atacama</span> </td> </tr> <tr> <td style="text-align:right;"> 4 </td> <td style="text-align:right;"> -99 </td> <td style="text-align:right;"> 1000000 </td> <td style="text-align:right;"> 800000 </td> <td style="text-align:left;"> <span style=" font-weight: bold; color: white !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: red !important;">NA</span> </td> </tr> <tr> <td style="text-align:right;"> 5 </td> <td style="text-align:right;"> NA </td> <td style="text-align:right;"> 1500000 </td> <td style="text-align:right;"> 810000 </td> <td style="text-align:left;"> <span style=" font-weight: bold; color: white !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: red !important;">NA</span> </td> </tr> </tbody> </table> ¿Qué podemos hacer para evitar que queden NA en la nueva columna? --- template: diapo-basica ## case_when Recodifiquemos las regiones: ```r regiones_cod = regiones %>% mutate(region_cod = case_when(region == 1 ~ 'Arica y Parinacota', region == 2 ~ 'Antofagasta', region == 3 ~ 'Atacama', * TRUE ~ 'Otra')) ``` -- <table class="table" style="margin-left: auto; margin-right: auto;"> <thead> <tr> <th style="text-align:right;"> id_fila </th> <th style="text-align:right;"> region </th> <th style="text-align:right;"> ingreso_promedio </th> <th style="text-align:right;"> ingreso_mediano </th> <th style="text-align:left;"> region_cod </th> </tr> </thead> <tbody> <tr> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 850000 </td> <td style="text-align:right;"> 450000 </td> <td style="text-align:left;"> <span style=" color: black !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: white !important;">Arica y Parinacota</span> </td> </tr> <tr> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 900000 </td> <td style="text-align:right;"> 650000 </td> <td style="text-align:left;"> <span style=" color: black !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: white !important;">Antofagasta</span> </td> </tr> <tr> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 950000 </td> <td style="text-align:right;"> 700000 </td> <td style="text-align:left;"> <span style=" color: black !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: white !important;">Atacama</span> </td> </tr> <tr> <td style="text-align:right;"> 4 </td> <td style="text-align:right;"> -99 </td> <td style="text-align:right;"> 1000000 </td> <td style="text-align:right;"> 800000 </td> <td style="text-align:left;"> <span style=" font-weight: bold; color: white !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: red !important;">Otra</span> </td> </tr> <tr> <td style="text-align:right;"> 5 </td> <td style="text-align:right;"> NA </td> <td style="text-align:right;"> 1500000 </td> <td style="text-align:right;"> 810000 </td> <td style="text-align:left;"> <span style=" font-weight: bold; color: white !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: red !important;">Otra</span> </td> </tr> </tbody> </table> Al añadir la condición `TRUE` al final (que siempre será evaluada como verdadera), agregamos un valor para cuando ninguna de las otras condiciones se haya cumplido. --- template: diapo-basica ## case_when Veamos un caso en que se cumpla más de una condición. Creemos categorías en base a condiciones arbitrarias: ```r regiones_cat = regiones %>% mutate(categoria = case_when(ingreso_promedio > 1000000 ~ '1', ingreso_mediano >= 800000 ~ '2', ingreso_mediano < 680000 ~ '3', TRUE ~ 'Otra')) ``` -- <table> <thead> <tr> <th style="text-align:right;"> id_fila </th> <th style="text-align:right;"> region </th> <th style="text-align:right;"> ingreso_promedio </th> <th style="text-align:right;"> ingreso_mediano </th> <th style="text-align:left;"> categoria </th> </tr> </thead> <tbody> <tr> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 850000 </td> <td style="text-align:right;"> 450000 </td> <td style="text-align:left;"> 3 </td> </tr> <tr> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 900000 </td> <td style="text-align:right;"> 650000 </td> <td style="text-align:left;"> 3 </td> </tr> <tr> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 950000 </td> <td style="text-align:right;"> 700000 </td> <td style="text-align:left;"> Otra </td> </tr> <tr> <td style="text-align:right;"> 4 </td> <td style="text-align:right;"> -99 </td> <td style="text-align:right;"> 1000000 </td> <td style="text-align:right;"> 800000 </td> <td style="text-align:left;"> 2 </td> </tr> <tr> <td style="text-align:right;"> 5 </td> <td style="text-align:right;"> NA </td> <td style="text-align:right;"> 1500000 </td> <td style="text-align:right;"> 810000 </td> <td style="text-align:left;"> 1 </td> </tr> </tbody> </table> --- template: diapo-basica ## case_when Ahora invirtamos la primera y la segunda condición: ```r *regiones_cat2 = regiones %>% mutate(categoria = case_when(ingreso_mediano >= 800000 ~ '2', * ingreso_promedio > 1000000 ~ '1', ingreso_mediano < 680000 ~ '3', TRUE ~ 'Otra')) ``` <table class="table" style="margin-left: auto; margin-right: auto;"> <thead> <tr> <th style="text-align:right;"> id_fila </th> <th style="text-align:right;"> region </th> <th style="text-align:right;"> ingreso_promedio </th> <th style="text-align:right;"> ingreso_mediano </th> <th style="text-align:left;"> categoria </th> </tr> </thead> <tbody> <tr> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 1 </td> <td style="text-align:right;"> 850000 </td> <td style="text-align:right;"> 450000 </td> <td style="text-align:left;"> <span style=" color: black !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: white !important;">3</span> </td> </tr> <tr> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 2 </td> <td style="text-align:right;"> 900000 </td> <td style="text-align:right;"> 650000 </td> <td style="text-align:left;"> <span style=" color: black !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: white !important;">3</span> </td> </tr> <tr> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 3 </td> <td style="text-align:right;"> 950000 </td> <td style="text-align:right;"> 700000 </td> <td style="text-align:left;"> <span style=" color: black !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: white !important;">Otra</span> </td> </tr> <tr> <td style="text-align:right;"> 4 </td> <td style="text-align:right;"> -99 </td> <td style="text-align:right;"> 1000000 </td> <td style="text-align:right;"> 800000 </td> <td style="text-align:left;"> <span style=" color: black !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: white !important;">2</span> </td> </tr> <tr> <td style="text-align:right;"> 5 </td> <td style="text-align:right;"> NA </td> <td style="text-align:right;"> 1500000 </td> <td style="text-align:right;"> 810000 </td> <td style="text-align:left;"> <span style=" font-weight: bold; color: white !important;border-radius: 4px; padding-right: 4px; padding-left: 4px; background-color: red !important;">2</span> </td> </tr> </tbody> </table> -- Es **sumamente importante** ser cuidadoso/a con el orden de las condiciones cuando puede cumplirse más de una, pues, como vimos, puede tener efectos imprevistos en las columnas creadas. --- class: center, middle .linea-superior[] .linea-inferior[] <img src="imagenes/logo_portada2.png" width="200" /> ## INE Educa: Clases abiertas de R ## Proyecto Ciencia de Datos ## Herramientas de edición de datos II