logo

Continuando con el tema de limpieza de datos, haremos una lista de funciones de la familia de librerías denominada: tidyverse. Vale la pena resaltar que esta librería es un compendido de muchas librerías de las cuales algunas mencionamos la clase pasada (tidyr,dplyr,tibble,stringr,ggplot2,purr,magrittr, etc)

Funciones principales
Función Utilidad
%>% “canalizar” (pasar) datos de una función a la siguiente
filter() mantener ciertas filas
selecct() mantener, eliminar, seleccionar o renombrar columnas
mutate() crear, transformar y redefinir columnas
arrange() ordenar las filas
recode() recodificar los valores de una columna
rename() cambiar el nombre de las columnas
clean_names() estandarizar la sintaxis de los nombres de las columnas
across() transformar varias columnas a la vez
as.character(), as.numeric(), as.Date(), … convertir el tipo de una columna
distinct() eliminar copias duplicadas de datos
rowwise() operaciones por/en cada fila
add_row() añadir filas manualmente
case_when() recodificar los valores de una columna con criterios lógicos más complejos
replace_na(),na_if(), coalesce() funciones especiales de recodificación
age_categories() y cut() crear grupos categóricos a partir de una columna
match_df() recodificación/limpieza de valores mediante un diccionario de datos
which() aplicar los criterios lógicos; devuelve los índices

Ejemplo práctico de limpieza de datos

Cargas librerías

El siguiente código muestra la carga de las librerías necesarias para el análisis. En este clase destacamos p_load() de pacman, que instala la librería si es necesario y lo carga para su uso. También puedes cargar los paquetes instalados con library() de R.

pacman::p_load(
  rio,        # importación/exportación de múltiples tipos de datos
  here,       # ruta relativa de los archivos
  janitor,    # limpieza de datos y tablas
  lubridate,  # trabajar con fechas
  epikit,     # función age_categories()
  tidyverse,  # gestión y visualización de datos 
  naniar      # evaluar y visualizar datos faltantes
  ) 

Importar datos

Trabajaremos con una base de datos muy importante sobre la simulación de un brote del virus del Ébola. Importamos el archivo Excel de la lista de casos “en bruto” utilizando la función import() de la librería rio. Esta librería maneja con flexibilidad muchos tipos de archivos (.xlsx, .csv, .tsv, .rds.). Consulta el documento sobre importar y exportar para obtener más información y consejos sobre situaciones inusuales (por ejemplo, omitir filas, establecer valores que faltan, importar hojas de Google, etc).

linelist_raw <- import("linelist_raw.xlsx")
DT::datatable(head(linelist_raw[,1:5],50))

Revisar datos

Puedes utilizar la función skim() del paquete skimr para obtener una visión general de todo la base de datos. Las columnas se resumen por clase o tipo, como por ejemplo: carácter, numérico. Nota: “POSIXct” es un tipo de fecha.

skimr::skim(linelist_raw)
Data summary
Name linelist_raw
Number of rows 6611
Number of columns 28
_______________________
Column type frequency:
character 17
numeric 8
POSIXct 3
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
case_id 137 0.98 6 6 0 5888 0
date onset 293 0.96 10 10 0 580 0
outcome 1500 0.77 5 7 0 2 0
gender 324 0.95 1 1 0 2 0
hospital 1512 0.77 5 36 0 13 0
infector 2323 0.65 6 6 0 2697 0
source 2323 0.65 5 7 0 2 0
age 107 0.98 1 2 0 75 0
age_unit 7 1.00 5 6 0 2 0
fever 258 0.96 2 3 0 2 0
chills 258 0.96 2 3 0 2 0
cough 258 0.96 2 3 0 2 0
aches 258 0.96 2 3 0 2 0
vomit 258 0.96 2 3 0 2 0
time_admission 844 0.87 5 5 0 1091 0
merged_header 0 1.00 1 1 0 1 0
…28 0 1.00 1 1 0 1 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
generation 7 1.00 16.60 5.71 0.00 13.00 16.00 20.00 37.00 ▁▆▇▂▁
lon 7 1.00 -13.23 0.02 -13.27 -13.25 -13.23 -13.22 -13.21 ▅▃▃▅▇
lat 7 1.00 8.47 0.01 8.45 8.46 8.47 8.48 8.49 ▅▇▇▇▆
row_num 0 1.00 3240.91 1857.83 1.00 1647.50 3241.00 4836.50 6481.00 ▇▇▇▇▇
wt_kg 7 1.00 52.69 18.59 -11.00 41.00 54.00 66.00 111.00 ▁▃▇▅▁
ht_cm 7 1.00 125.25 49.57 4.00 91.00 130.00 159.00 295.00 ▂▅▇▂▁
ct_blood 7 1.00 21.26 1.67 16.00 20.00 22.00 22.00 26.00 ▁▃▇▃▁
temp 158 0.98 38.60 0.95 35.20 38.30 38.80 39.20 40.80 ▁▂▂▇▁

Variable type: POSIXct

skim_variable n_missing complete_rate min max median n_unique
infection date 2322 0.65 2012-04-09 2015-04-27 2014-10-04 538
hosp date 7 1.00 2012-04-20 2015-04-30 2014-10-15 570
date_of_outcome 1068 0.84 2012-05-14 2015-06-04 2014-10-26 575

Nombres de columnas

En R, los nombres de las columnas son la “cabecera” o el valor “superior” de una columna. Se utilizan para referirse a las columnas en el código, y sirven como etiqueta por defecto en las figuras.

Otros programas estadísticos, como SAS y STATA, utilizan “etiquetas” que coexisten como versiones impresas más largas de los nombres de columna más cortos. Aunque R ofrece la posibilidad de añadir etiquetas de columna a los datos, no es una práctica que sea muy utilizada. Para hacer que los nombres de las columnas sean “fáciles de imprimir” para las figuras, normalmente se ajusta su visualización dentro de los comandos de gráficas que crean las salidas (por ejemplo, los títulos de los ejes o de las leyendas de una gráfica, o las cabeceras de las columnas en una tabla impresa).

Como los nombres de las columnas de R se utilizan con mucha frecuencia, deben tener una sintaxis “limpia”. Se sugieren lo siguiente:

  • Nombres cortos.
  • Sin espacios (sustituir por barras bajas _ ).
  • Sin caracteres inusuales (&, #, <, >, …).
  • Nomenclatura de estilo similar (por ejemplo, todas las columnas de fecha nombradas como date_onset, date_report, date_death).
names(linelist_raw)
##  [1] "case_id"         "generation"      "infection date"  "date onset"     
##  [5] "hosp date"       "date_of_outcome" "outcome"         "gender"         
##  [9] "hospital"        "lon"             "lat"             "infector"       
## [13] "source"          "age"             "age_unit"        "row_num"        
## [17] "wt_kg"           "ht_cm"           "ct_blood"        "fever"          
## [21] "chills"          "cough"           "aches"           "vomit"          
## [25] "temp"            "time_admission"  "merged_header"   "...28"

Podemos ver que los nombres de las columnas de nuestra base de datos inicialmente:

  • Contienen espacios (por ejemplo: “infection date”).
  • Se utilizan diferentes patrones de nomenclatura para las fechas (por ejemplo: “date onset” vs. “infection date”).
  • Al parecer se aplicó alguna función para fusionar columnas. Lo podemos ver dado que existe una columna llamada “merged_header” y la siguiente columna se le asignó “…28” (seguramente estaba vacía y es la columna 28).

Limpieza automática

La función clean_names() del paquete janitor estandariza los nombres de las columnas y los hace únicos haciendo lo siguiente:

  • Convierte todos los nombres para que estén compuestos sólo por barras bajas, números y letras.
  • Los caracteres acentuados se transliteran (por ejemplo, la “ó” con tilde se convierte en “o”, la “ñ” se convierte en “n”).
  • Se puede especificar la preferencia de mayúsculas para los nuevos nombres de columna utilizando case = argumento (“snake” es el valor por defecto, las alternativas incluyen “sentence”, “title”, “small_camel”,…).
  • Puedes especificar sustituciones de nombres concretos proporcionando un vector(por ejemplo, replace = c(onset = "date_of_onset")).

Para más información de esta librería, puedes consultar:Janitor

# Renombrar columnas automaticamente
linelist <- linelist_raw %>% 
            janitor::clean_names()
names(linelist)
##  [1] "case_id"         "generation"      "infection_date"  "date_onset"     
##  [5] "hosp_date"       "date_of_outcome" "outcome"         "gender"         
##  [9] "hospital"        "lon"             "lat"             "infector"       
## [13] "source"          "age"             "age_unit"        "row_num"        
## [17] "wt_kg"           "ht_cm"           "ct_blood"        "fever"          
## [21] "chills"          "cough"           "aches"           "vomit"          
## [25] "temp"            "time_admission"  "merged_header"   "x28"

Limpieza manual

A menudo es necesario renombrar las columnas manualmente, incluso después del paso anterior. Renombrar variables lo podemos hacer con la función rename(), como parte de una cadena de pipes. Esta función utiliza el estilo nombre_nuevo = nombre_anterior (el nombre nuevo de la columna se escribe antes que el antiguo).

# Renombrar columnas manualmente
linelist <- linelist_raw %>% 
            janitor::clean_names() %>% 
                  # nombre nuevo        # nombre anterior
            rename(date_infection       =  infection_date,
                   date_hosp            =  hosp_date,
                   date_outcome         =  date_of_outcome)
names(linelist)
##  [1] "case_id"        "generation"     "date_infection" "date_onset"    
##  [5] "date_hosp"      "date_outcome"   "outcome"        "gender"        
##  [9] "hospital"       "lon"            "lat"            "infector"      
## [13] "source"         "age"            "age_unit"       "row_num"       
## [17] "wt_kg"          "ht_cm"          "ct_blood"       "fever"         
## [21] "chills"         "cough"          "aches"          "vomit"         
## [25] "temp"           "time_admission" "merged_header"  "x28"

También puedes renombrar por la posición de la columna, en lugar del nombre de la columna, por ejemplo:

linelist <- linelist %>% 
            rename(id    = 1,
                   Group = 2)
names(linelist)
##  [1] "id"             "Group"          "date_infection" "date_onset"    
##  [5] "date_hosp"      "date_outcome"   "outcome"        "gender"        
##  [9] "hospital"       "lon"            "lat"            "infector"      
## [13] "source"         "age"            "age_unit"       "row_num"       
## [17] "wt_kg"          "ht_cm"          "ct_blood"       "fever"         
## [21] "chills"         "cough"          "aches"          "vomit"         
## [25] "temp"           "time_admission" "merged_header"  "x28"

Como método abreviado, también puedes cambiar el nombre de las columnas dentro de las funciones select() y summarise(). Estas funciones también utilizan el formato nombre_nuevo = nombre_anterior.

# Selecciona y renombra estas columnas:
Select_linelist_raw <- linelist_raw %>% 
  select(# nombre nuevo       # nombre anterior
         date_infection       = `infection date`,    
         date_hosp            = `hosp date`)
names(Select_linelist_raw)
## [1] "date_infection" "date_hosp"

Seleccionar o reordenar columnas

Como ya vimos en la clase anterior, la función select(), nos ayuda a seleccionar sólo las columnas que necesitemos conservar, pero también puede servir para especificar el orden que deseamos.

Por ejemplo, si deseas reordenar las columnas, everything() es un argumento útil para indicar “todas las demás columnas no mencionadas”

# mueve date_onset y date_hospitalisation al principio
linelist %>% 
  select(date_onset, date_hosp, everything()) %>% 
  names()
##  [1] "date_onset"     "date_hosp"      "id"             "Group"         
##  [5] "date_infection" "date_outcome"   "outcome"        "gender"        
##  [9] "hospital"       "lon"            "lat"            "infector"      
## [13] "source"         "age"            "age_unit"       "row_num"       
## [17] "wt_kg"          "ht_cm"          "ct_blood"       "fever"         
## [21] "chills"         "cough"          "aches"          "vomit"         
## [25] "temp"           "time_admission" "merged_header"  "x28"

Hay un gran número de argumentos de ayuda que también funcionan dentro de las funciones como: select(), across() y summarise():

  • last_col(): la última columna.
  • where(): aplica una función lógica a todas las columnas y selecciona las que cumplen.
  • contains(): columnas que contienen una cadena de caracteres.
    • Ejemplo: select(contains("time")).
  • starts_with():coincide con un prefijo especificado.
    • Ejemplo: select(starts_with("date_")).
  • ends_with(): coincide con un sufijo especificado.
    • Ejemplo: select(ends_with("_post)).
  • matches(): para aplicar una expresión regular.
    • Ejemplo: select(matches("[pt]al")).
  • num_range(): un rango numérico como x01, x02, x03.
  • any_of(): coincide con la columna SI existe pero no devuelve ningún error si no se encuentra.
    • Ejemplo: select(any_of(date_onset, date_death, cardiac_arrest)).

Además, utiliza operadores ya trabajados como c() para listar varias columnas, : para columnas consecutivas, ! para opuestos, & para “y” y | para “o”.

Algunos ejemplos de la utilidad de estos argumentos:

# selecciona las columnas que son de clase Numeric
linelist %>% 
  select(where(is.numeric)) %>% 
  names()
## [1] "Group"    "lon"      "lat"      "row_num"  "wt_kg"    "ht_cm"    "ct_blood"
## [8] "temp"
# selecciona las columnas que contienen ciertos caracteres
linelist %>% 
  select(contains("date")) %>% 
  names()
## [1] "date_infection" "date_onset"     "date_hosp"      "date_outcome"
# selecciona las columnas id y age-related
linelist %>% 
  select(id, contains("age")) %>%   
  names()
## [1] "id"       "age"      "age_unit"
# selecciona por multiples coincidencias de caracteres
linelist %>% 
  select(matches("onset|hosp|fev")) %>%   
  names()
## [1] "date_onset" "date_hosp"  "hospital"   "fever"

Nota importante: en este último ejemplo, si has escrito un nombre de columna y no existen datos para ella, puede devolver un error y detener tu código. Considera el uso del argumento any_of() para citar columnas que pueden o no existir, especialmente útil en selecciones negativas (eliminar).

linelist %>% 
  select(any_of(c("date_onset", "village_origin", "village_detection", "village_residence", "village_travel"))) %>% 
  names()
## [1] "date_onset"

Eliminar datos duplicados

Es una tarea muy importante en la limpieza de datos y muy complicada de realizar de forma manual.

Encontrar y eliminar registros duplicadas

Para revisar las filas que tienen duplicados, puedes utilizar la función get_dupes() del paquete janitor. Las filas devueltas por la función están 100% duplicadas considerando los valores de todas las columnas.

linelist %>% 
  janitor::get_dupes()
##     id Group date_infection date_onset  date_hosp date_outcome outcome gender
## 1 <NA>    16     2014-10-22 2014-11-03 2014-11-05   2014-11-16    <NA>      f
## 2 <NA>    16     2014-10-22 2014-11-03 2014-11-05   2014-11-16    <NA>      f
## 3 <NA>    20     2014-12-25 2015-01-04 2015-01-06   2015-01-16 Recover      m
## 4 <NA>    20     2014-12-25 2015-01-04 2015-01-06   2015-01-16 Recover      m
##            hospital       lon      lat infector source age age_unit row_num
## 1 Military Hospital -13.21947 8.483222   f17d9f  other  34    years    2987
## 2 Military Hospital -13.21947 8.483222   f17d9f  other  34    years    2987
## 3 Military Hospital -13.23220 8.472805   994b0d  other  44    years    3811
## 4 Military Hospital -13.23220 8.472805   994b0d  other  44    years    3811
##   wt_kg ht_cm ct_blood fever chills cough aches vomit temp time_admission
## 1    70   178       21   yes     no   yes    no    no 38.6          14:42
## 2    70   178       21   yes     no   yes    no    no 38.6          14:42
## 3    78   190       21   yes     no   yes    no    no 38.5          17:08
## 4    78   190       21   yes     no   yes    no    no 38.5          17:08
##   merged_header x28 dupe_count
## 1             a   b          2
## 2             a   b          2
## 3             a   b          2
## 4             a   b          2

Observemos que crea una columna dupe_count que indica el número de eces que encontró la observación repetida. También se pueden encontrar duplicados de algunas columnas especificas. Si no quieres ver toda la lista, pues pueden ser extensa, simplemente puedes contar los duplicados que cumplan la condición dada.

linelist %>% 
  janitor::get_dupes(-gender)
##     id Group date_infection date_onset  date_hosp date_outcome outcome
## 1 <NA>    16     2014-10-22 2014-11-03 2014-11-05   2014-11-16    <NA>
## 2 <NA>    16     2014-10-22 2014-11-03 2014-11-05   2014-11-16    <NA>
## 3 <NA>    20     2014-12-25 2015-01-04 2015-01-06   2015-01-16 Recover
## 4 <NA>    20     2014-12-25 2015-01-04 2015-01-06   2015-01-16 Recover
##            hospital       lon      lat infector source age age_unit row_num
## 1 Military Hospital -13.21947 8.483222   f17d9f  other  34    years    2987
## 2 Military Hospital -13.21947 8.483222   f17d9f  other  34    years    2987
## 3 Military Hospital -13.23220 8.472805   994b0d  other  44    years    3811
## 4 Military Hospital -13.23220 8.472805   994b0d  other  44    years    3811
##   wt_kg ht_cm ct_blood fever chills cough aches vomit temp time_admission
## 1    70   178       21   yes     no   yes    no    no 38.6          14:42
## 2    70   178       21   yes     no   yes    no    no 38.6          14:42
## 3    78   190       21   yes     no   yes    no    no 38.5          17:08
## 4    78   190       21   yes     no   yes    no    no 38.5          17:08
##   merged_header x28 dupe_count gender
## 1             a   b          2      f
## 2             a   b          2      f
## 3             a   b          2      m
## 4             a   b          2      m

Para eliminar estas filas encontradas repetidas, utiliza la función distinct(). Las filas duplicadas se eliminan de forma que sólo se conserva la primera de dichas filas.

# dimensión con duplicados
dim(linelist)
## [1] 6611   28
linelist <- linelist %>% 
  distinct()
# dimensión sin duplicados
dim(linelist)
## [1] 6609   28

Manejo de datos faltantes

# Datos faltantes por columna
gg_miss_var(linelist)

# Gráfico de valores faltantes en todo el dataframe
vis_miss(linelist)

Existen varias funciones útiles para el manejo de datos faltantes. Como lo son:

  • pct_miss(): puedes ver tres variantes de esta función, las cuales encuentran el porcentaje de valores faltantes según la especificación.
# Porcentaje de TODOS los valores faltantes
pct_miss(linelist)
## [1] 7.7027
# Porcentaje de filas en las que falta algún valor
pct_miss_case(linelist)   # usa n_complete() para los recuentos
## [1] 76.15373
## [1] 69.12364
# Porcentaje de filas que están completas (no faltan valores) 
pct_complete_case(linelist) # usa n_complete() para los recuentos
## [1] 23.84627
  • is.na() y !is.na(): utiliza is.na() para identificar los valores que faltan, o utiliza su opuesto (con ! delante) para identificar los valores que no faltan. Ambos devuelven un valor lógico (TRUE o FALSE). Recuerda que puedes sumar (sum()) el vector resultante para contar el número de TRUE.
sum(is.na(linelist$date_outcome))
## [1] 1068
  • na.omit(): esta función eliminará las filas con valores faltantes.
my_vector <- c(1, 56, NA, 5, NA, 22)
na.omit(my_vector)
## [1]  1 56  5 22
## attr(,"na.action")
## [1] 3 5
## attr(,"class")
## [1] "omit"
  • na.rm = TRUE: cuando se ejecuta alguna función matemática como max(), min(), sum() o mean(), si hay algún valor NA presente el valor devuelto será NA. Este comportamiento por defecto es intencionado, para avisar que falta algún dato.

Puedes evitarlo eliminando los valores faltantes del cálculo. Para ello, incluye el argumento na.rm = TRUE (significa “eliminar NA”).

mean(my_vector)  
## [1] NA
mean(my_vector, na.rm = TRUE)
## [1] 21
  • drop_na(): si se ejecuta con los paréntesis vacíos, elimina las filas con valores faltantes. Si se especifican los nombres de las columnas en los paréntesis, se eliminarán las filas con valores faltantes en esas columnas.
linelist3 <- linelist %>% 
  drop_na(source, infector, date_infection) 
dim(linelist)
## [1] 6609   28
dim(linelist3)
## [1] 4286   28

Creación y trasformación de columnas

Recomendamos que podemos utilizar la función mutate() para añadir una nueva columna, o para modificar una existente.

Nuevas columnas

Se pueden crear nuevas columnas realizando operaciones con las demás columnas.

linelist <- linelist %>% 
            mutate(bmi = wt_kg / (ht_cm/100)^2)
names(linelist)
##  [1] "id"             "Group"          "date_infection" "date_onset"    
##  [5] "date_hosp"      "date_outcome"   "outcome"        "gender"        
##  [9] "hospital"       "lon"            "lat"            "infector"      
## [13] "source"         "age"            "age_unit"       "row_num"       
## [17] "wt_kg"          "ht_cm"          "ct_blood"       "fever"         
## [21] "chills"         "cough"          "aches"          "vomit"         
## [25] "temp"           "time_admission" "merged_header"  "x28"           
## [29] "bmi"

También simplemente colocando un valor fijo.

linelist <- linelist %>% 
            mutate(new_col = 10) 
names(linelist)
##  [1] "id"             "Group"          "date_infection" "date_onset"    
##  [5] "date_hosp"      "date_outcome"   "outcome"        "gender"        
##  [9] "hospital"       "lon"            "lat"            "infector"      
## [13] "source"         "age"            "age_unit"       "row_num"       
## [17] "wt_kg"          "ht_cm"          "ct_blood"       "fever"         
## [21] "chills"         "cough"          "aches"          "vomit"         
## [25] "temp"           "time_admission" "merged_header"  "x28"           
## [29] "bmi"            "new_col"

Transformar el tipo de columna

Las columnas que contienen valores que son fechas, números o valores lógicos (TRUE/FALSE) sólo se comportarán como se espera si están correctamente clasificadas. Hay una diferencia entre “2” de tipo carácter y 2 de tipo numérico.

Vimos al inicio con ayuda de la función skim(), como R guardo el tipo de cada variable. Por ejemplo: el tipo de la columna age es un carácter, pero esto no es correcto. Para realizar análisis cuantitativos, ¡necesitamos que estos números sean reconocidos como numéricos!.

# Tipo original
class(linelist$age)
## [1] "character"
linelist <- linelist %>% 
  mutate(age = as.numeric(age))

# Variable trasformada
class(linelist$age)
## [1] "numeric"

De forma similar, puedes utilizar as.character() y as.logical(), as.Date, factor().

Otro problema que podemos visualizar en las variables, es que por ejemplo: date_onset aparece como carácter, pero para cualquier análisis esta variable debe ser reconocida como fecha.

# Tipo original
class(linelist$date_onset)
## [1] "character"
linelist <- linelist %>% 
            mutate(date_onset = as.Date(date_onset))

# Tipo original
class(linelist$date_onset)
## [1] "Date"

Datos agrupados

También podemos aprovechar la función group_by() para hacer transformaciones por medio de grupos.

# Edad normalizada para hacer la media de TODAS las filas
linelist1 <- linelist %>% select(age) %>%
             mutate(age_norm = (age - mean(age, na.rm=T))/ sd(age, na.rm=T))
head(linelist1)
##   age     age_norm
## 1   2 -1.117313654
## 2   3 -1.038052358
## 3  56  3.162796350
## 4  18  0.150867088
## 5   3 -1.038052358
## 6  16 -0.007655505
# Edad normalizada para hacer la media por grupo de hospital
linelist2 <- linelist %>% select(age,hospital) %>%
             group_by(hospital) %>% 
             mutate(age_norm = (age - mean(age, na.rm=T))/ sd(age, na.rm=T))
head(linelist2)
## # A tibble: 6 × 3
## # Groups:   hospital [5]
##     age hospital                             age_norm
##   <dbl> <chr>                                   <dbl>
## 1     2 Other                                 -1.13  
## 2     3 <NA>                                  -1.01  
## 3    56 St. Mark's Maternity Hospital (SMMH)   3.38  
## 4    18 Port Hospital                          0.132 
## 5     3 Military Hospital                     -1.05  
## 6    16 Port Hospital                         -0.0262

Transformar múltiples columnas

A menudo, para escribir un código conciso, se desea aplicar la misma transformación a varias columnas a la vez. Se puede aplicar una transformación a varias columnas a la vez utilizando el argumento across().

linelist <- linelist %>% 
  mutate(across(.cols = c(temp, ht_cm, wt_kg), .fns = as.character))

También se puede crear una nueva variable por medio de múltiples existentes.

linelist <- linelist %>%
# crear la columna age_years (A partir de age y age_unit)
          mutate(age_years = case_when(
            age_unit == "years" ~ age,
            age_unit == "months" ~ age/12,
            is.na(age_unit) ~ age))

Discretización de columnas

En algunas ocasiones es importante cambiar una variable numérica a categórica. Algunos ejemplos comunes son las categorías de edad, los grupos de valores de laboratorio, etc.

class(linelist$age_years)
## [1] "numeric"
# Examine la distribución
hist(linelist$age_years,xlab=" ",main=" ",col="lightblue")

summary(linelist$age_years, na.rm=T)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##    0.00    6.00   13.00   16.04   23.00   84.00     107

Con ayuda de la función age_categories() puedes categorizar y etiquetar fácilmente las columnas numéricas.

linelist <- linelist %>% 
            mutate(age_cat = age_categories(    # crear una columna nueva
                             age_years,         # columna numérica para hacer grupos
                             breakers = c(0, 5, 10, 15, 20, 30, 40, 50, 60, 70)))

table(linelist$age_cat, useNA = "always")
## 
##   0-4   5-9 10-14 15-19 20-29 30-39 40-49 50-59 60-69   70+  <NA> 
##  1227  1223  1048   828  1216   597   251    78    27     7   107

Los valores de ruptura que especificas son por defecto los límites inferiores. Es decir, están incluidos en el grupo “superior”, los grupos están “abiertos” en la parte inferior/izquierda. Pero se puede hacer lo contrario si se desea.

# Crear una nueva variable, cortando la variable numérica age
# Se excluye el corte inferior pero se incluye el superior en cada categoría
linelist <- linelist %>% 
  mutate(
    age_cat = cut(
      age_years,
      breaks = c(0, 5, 10, 15, 20,
                 30, 50, 70, 100),
      include.lowest = TRUE         # # incluye 0 en el grupo más bajo
      ))

# tabular el número de observaciones por grupo
table(linelist$age_cat, useNA = "always")
## 
##    [0,5]   (5,10]  (10,15]  (15,20]  (20,30]  (30,50]  (50,70] (70,100] 
##     1469     1195     1041      770     1149      778       94        6 
##     <NA> 
##      107

También se pueden hacer las divisiones por medio de los cuartiles.

quantile(linelist$age_years,na.rm = TRUE)  
##   0%  25%  50%  75% 100% 
##    0    6   13   23   84

O especificando los percentiles.

quantile(linelist$age_years,               
  probs = c(0, .25, .50, .75, .90, .95),   
  na.rm = TRUE)   
##  0% 25% 50% 75% 90% 95% 
##   0   6  13  23  33  41

\[ \]