Análisis de Datos I

Semana 4: Gestión de bases de datos y calidad del dato

Dr(c). César Marcelo Ávila Fuentes

2026-04-06

Semana 4

Gestión de bases de datos y calidad del dato

  • Missing
  • Duplicados
  • Tipos de variables
  • Principios tidy
  • Operaciones básicas de gestión en R

Objetivo de la clase

Al finalizar esta sesión, se espera que puedan:

  • comprender qué significa trabajar con una base de datos de buena calidad
  • identificar problemas frecuentes en bases reales
  • ejecutar operaciones básicas de gestión de datos en R
  • preparar una base para etapas posteriores de análisis descriptivo

Idea central

Una base de datos no se analiza tal como llega.

Antes de describir, visualizar o interpretar, es necesario revisar:

  • su estructura
  • la calidad del dato
  • los nombres de las variables
  • los tipos de datos
  • los valores perdidos
  • los duplicados
  • la consistencia de las categorías

¿Qué es gestionar una base de datos?

Gestionar una base de datos implica:

  • revisar cómo está organizada
  • corregir errores
  • ordenar variables y observaciones
  • transformar información cuando sea necesario
  • dejar registro de las decisiones tomadas

¿Qué problemas aparecen en bases reales?

Con frecuencia encontramos:

  • nombres de variables poco claros
  • respuestas mal escritas
  • categorías inconsistentes
  • variables mal tipadas
  • celdas vacías
  • registros duplicados
  • columnas irrelevantes
  • observaciones que no corresponden al análisis

Antes de limpiar: tres preguntas básicas

  • 1. ¿Qué representa una fila?

  • Una observación.

  • 2. ¿Qué representa una columna?

  • Una variable.

  • 3. ¿Qué representa una celda?

  • El valor de una variable en una observación específica.

Principio tidy

Una base ordenada sigue, idealmente, tres criterios:

  • cada fila representa una observación
  • cada columna representa una variable
  • cada celda contiene un solo valor

Ejemplo de estructura poco ordenada

comuna gasto_salud_2023 gasto_educ_2023 gasto_seg_2023
Temuco 100.000.000 150.000.000 60.000.000
P. Las Casas 80.000.000 120.000.000 40.000.000

Ejemplo de estructura más ordenada

comuna area gasto
Temuco Salud 100.000.000
Temuco Educación 150.000.000
Temuco Seguridad 60.000.000
Padre Las Casas Salud 80.000.000

Calidad del dato

Cuando revisamos calidad del dato, nos fijamos en:

  • completitud Si la base contiene la información necesaria y no existen valores faltantes que afecten el análisis
  • consistencia Que los datos mantengan un criterio uniforme en su escritura, codificación y estructura
  • validez Que los valores registrados tengan sentido y correspondan realmente a lo que la variable busca medir
  • unicidad que no existan registros duplicados, que cambien porcentajes, promedios, etc.
  • tipo correcto de cada variable que cada variable esté almacenada en el formato adecuado.

Paquetes

library(dplyr)
#Sirve para manipular bases de datos (filtrar, seleccionar, ordenar y crear variables)
library(tidyr)
#Para ordenar y reorganizar datos, especialmente para pasar bases entre formato ancho y largo
library(stringr)
#Para trabajar con texto y cadenas de caracteres
library(lubridate)
#Para manejar fechas y horas, facilitando su lectura y transformación
library(janitor)
#Para limpiar bases de datos (arreglar nombres de variables y revisar tablas de frecuencia)
library(skimr)
#Para hacer un resumen rápido y descriptivo de una base de datos o de sus variables
library(here)
#para trabajar con rutas de archivos de manera ordenada, sin depender de escribir la ruta completa de forma manual

Base de ejemplo para la clase

Base <- tibble::tibble(
  id = c(1, 2, 3, 3, 4, 5),
  `Nombre Comuna` = c("Temuco ", "temuco", "P. Las Casas", "P. Las Casas", "Villarrica", "Temuco"),
  nombre_region = c("La Araucanía", "La Araucanía", "La Araucanía", "La Araucanía", "La Araucanía", "Los Ríos"),
  MONTO = c("120000", "Sin dato", "540000", "540000", NA, "300000"),
  Fecha = c("01-04-2026", "02-04-2026", "03-04-2026", "03-04-2026", "05-04-2026", "06-04-2026"),
  sexo = c("M", "F", "No responde", "No responde", "F", "M"),
  edad = c(23, 35, 17, 17, 61, 29),
  tramo = c("Activo", "Activo", "Sin información", "Sin información", "Activo", "Activo"),
  Observaciones = c("ok", "revisar", "ok", "duplicado", "falta monto", "otra región")
)

Base
# A tibble: 6 × 9
     id `Nombre Comuna` nombre_region MONTO    Fecha      sexo        edad tramo
  <dbl> <chr>           <chr>         <chr>    <chr>      <chr>      <dbl> <chr>
1     1 "Temuco "       La Araucanía  120000   01-04-2026 M             23 Acti…
2     2 "temuco"        La Araucanía  Sin dato 02-04-2026 F             35 Acti…
3     3 "P. Las Casas"  La Araucanía  540000   03-04-2026 No respon…    17 Sin …
4     3 "P. Las Casas"  La Araucanía  540000   03-04-2026 No respon…    17 Sin …
5     4 "Villarrica"    La Araucanía  <NA>     05-04-2026 F             61 Acti…
6     5 "Temuco"        Los Ríos      300000   06-04-2026 M             29 Acti…
# ℹ 1 more variable: Observaciones <chr>

Primer paso: mirar la base

names(Base)
[1] "id"            "Nombre Comuna" "nombre_region" "MONTO"        
[5] "Fecha"         "sexo"          "edad"          "tramo"        
[9] "Observaciones"
dim(Base)
[1] 6 9
head(Base)
# A tibble: 6 × 9
     id `Nombre Comuna` nombre_region MONTO    Fecha      sexo        edad tramo
  <dbl> <chr>           <chr>         <chr>    <chr>      <chr>      <dbl> <chr>
1     1 "Temuco "       La Araucanía  120000   01-04-2026 M             23 Acti…
2     2 "temuco"        La Araucanía  Sin dato 02-04-2026 F             35 Acti…
3     3 "P. Las Casas"  La Araucanía  540000   03-04-2026 No respon…    17 Sin …
4     3 "P. Las Casas"  La Araucanía  540000   03-04-2026 No respon…    17 Sin …
5     4 "Villarrica"    La Araucanía  <NA>     05-04-2026 F             61 Acti…
6     5 "Temuco"        Los Ríos      300000   06-04-2026 M             29 Acti…
# ℹ 1 more variable: Observaciones <chr>

Primer paso: mirar la base

str(Base)
tibble [6 × 9] (S3: tbl_df/tbl/data.frame)
 $ id           : num [1:6] 1 2 3 3 4 5
 $ Nombre Comuna: chr [1:6] "Temuco " "temuco" "P. Las Casas" "P. Las Casas" ...
 $ nombre_region: chr [1:6] "La Araucanía" "La Araucanía" "La Araucanía" "La Araucanía" ...
 $ MONTO        : chr [1:6] "120000" "Sin dato" "540000" "540000" ...
 $ Fecha        : chr [1:6] "01-04-2026" "02-04-2026" "03-04-2026" "03-04-2026" ...
 $ sexo         : chr [1:6] "M" "F" "No responde" "No responde" ...
 $ edad         : num [1:6] 23 35 17 17 61 29
 $ tramo        : chr [1:6] "Activo" "Activo" "Sin información" "Sin información" ...
 $ Observaciones: chr [1:6] "ok" "revisar" "ok" "duplicado" ...
summary(Base)
       id       Nombre Comuna      nombre_region         MONTO          
 Min.   :1.00   Length:6           Length:6           Length:6          
 1st Qu.:2.25   Class :character   Class :character   Class :character  
 Median :3.00   Mode  :character   Mode  :character   Mode  :character  
 Mean   :3.00                                                           
 3rd Qu.:3.75                                                           
 Max.   :5.00                                                           
    Fecha               sexo                edad          tramo          
 Length:6           Length:6           Min.   :17.00   Length:6          
 Class :character   Class :character   1st Qu.:18.50   Class :character  
 Mode  :character   Mode  :character   Median :26.00   Mode  :character  
                                       Mean   :30.33                     
                                       3rd Qu.:33.50                     
                                       Max.   :61.00                     
 Observaciones     
 Length:6          
 Class :character  
 Mode  :character  
                   
                   
                   

Revisión general con skim()

skim(Base)
Data summary
Name Base
Number of rows 6
Number of columns 9
_______________________
Column type frequency:
character 7
numeric 2
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
Nombre Comuna 0 1.00 6 12 0 5 0
nombre_region 0 1.00 8 12 0 2 0
MONTO 1 0.83 6 8 0 4 0
Fecha 0 1.00 10 10 0 5 0
sexo 0 1.00 1 11 0 3 0
tramo 0 1.00 6 15 0 2 0
Observaciones 0 1.00 2 11 0 5 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
id 0 1 3.00 1.41 1 2.25 3 3.75 5 ▃▃▇▃▃
edad 0 1 30.33 16.57 17 18.50 26 33.50 61 ▇▂▂▁▂

Limpiar nombres de variables

names(Base)
[1] "id"            "Nombre Comuna" "nombre_region" "MONTO"        
[5] "Fecha"         "sexo"          "edad"          "tramo"        
[9] "Observaciones"
Base <- Base |>
  clean_names()

# clean_names() pasa todo a minúsculas, reemplaza espacios por guiones bajos, quita las tildes, símbolos o caracteres problemáticos
#necesitas tener cargado janitor

names(Base)
[1] "id"            "nombre_comuna" "nombre_region" "monto"        
[5] "fecha"         "sexo"          "edad"          "tramo"        
[9] "observaciones"

¿Por qué limpiar nombres?

Esto permite:

  • evitar espacios
  • evitar mayúsculas innecesarias
  • eliminar caracteres incómodos
  • trabajar con nombres más consistentes

Ejemplo:

  • Nombre Comunanombre_comuna
  • Monto Total $monto_total

Renombrar un objeto

base_municipal <- Base
rm(Base)
ls()
[1] "base_municipal"

Volver al nombre original

Base <- base_municipal
#duplica el objeto base_municipal en un nuevo objeto llamado Base
rm(base_municipal)
#Elimina el objeto base_municipal
ls()
[1] "Base"
# ls() muestra los objetos que actualmente están guardados en el entorno de trabajo

Eliminar objetos

rm(base_municipal)
rm(objeto1, objeto2, objeto3)

Renombrar una variable dentro de una base

names(Base)
[1] "id"            "nombre_comuna" "nombre_region" "monto"        
[5] "fecha"         "sexo"          "edad"          "tramo"        
[9] "observaciones"
Base <- Base |>
  rename(comuna = nombre_comuna)
#Con rename cambiamos el nombre de una variable
# Se necesita el paquete dplyr

names(Base)
[1] "id"            "comuna"        "nombre_region" "monto"        
[5] "fecha"         "sexo"          "edad"          "tramo"        
[9] "observaciones"

Renombrar varias variables

names(Base)
[1] "id"            "comuna"        "nombre_region" "monto"        
[5] "fecha"         "sexo"          "edad"          "tramo"        
[9] "observaciones"
Base <- Base |>
  rename(
    region = nombre_region,
    monto_texto = monto
  )

names(Base)
[1] "id"            "comuna"        "region"        "monto_texto"  
[5] "fecha"         "sexo"          "edad"          "tramo"        
[9] "observaciones"

Eliminar variables dentro de un objeto

Basesinobs <- Base |> 
  select(-observaciones)

#Toma el objeto Base, selecciona todas las variables menos observaciones y guarda esta nueva versión en un nuevo objeto llamado Basesinobs

Eliminar varias variables

Basesinobs <- Base |>
  select(-observaciones, -tramo)

Seleccionar solo las variables que quiero mantener

Base2 <- Base |>
  select(comuna, region, monto_texto, fecha, sexo)

Eliminar observaciones de un objeto

BasesinAraucanía <- Base |>
  filter(region == "La Araucanía")

Otro ejemplo de filtrado

Base |>
  filter(!is.na(monto_texto))
# A tibble: 5 × 9
     id comuna         region  monto_texto fecha sexo   edad tramo observaciones
  <dbl> <chr>          <chr>   <chr>       <chr> <chr> <dbl> <chr> <chr>        
1     1 "Temuco "      La Ara… 120000      01-0… M        23 Acti… ok           
2     2 "temuco"       La Ara… Sin dato    02-0… F        35 Acti… revisar      
3     3 "P. Las Casas" La Ara… 540000      03-0… No r…    17 Sin … ok           
4     3 "P. Las Casas" La Ara… 540000      03-0… No r…    17 Sin … duplicado    
5     5 "Temuco"       Los Rí… 300000      06-0… M        29 Acti… otra región  

Eliminar una respuesta específica dentro de una variable

Base |>
  filter(sexo != "No responde")
# A tibble: 4 × 9
     id comuna       region    monto_texto fecha sexo   edad tramo observaciones
  <dbl> <chr>        <chr>     <chr>       <chr> <chr> <dbl> <chr> <chr>        
1     1 "Temuco "    La Arauc… 120000      01-0… M        23 Acti… ok           
2     2 "temuco"     La Arauc… Sin dato    02-0… F        35 Acti… revisar      
3     4 "Villarrica" La Arauc… <NA>        05-0… F        61 Acti… falta monto  
4     5 "Temuco"     Los Ríos  300000      06-0… M        29 Acti… otra región  

Otro ejemplo de eliminación de categoría

Base |>
  filter(tramo != "Sin información")
# A tibble: 4 × 9
     id comuna       region    monto_texto fecha sexo   edad tramo observaciones
  <dbl> <chr>        <chr>     <chr>       <chr> <chr> <dbl> <chr> <chr>        
1     1 "Temuco "    La Arauc… 120000      01-0… M        23 Acti… ok           
2     2 "temuco"     La Arauc… Sin dato    02-0… F        35 Acti… revisar      
3     4 "Villarrica" La Arauc… <NA>        05-0… F        61 Acti… falta monto  
4     5 "Temuco"     Los Ríos  300000      06-0… M        29 Acti… otra región  

Advertencia metodológica

Eliminar observaciones no es una decisión neutral.

Antes de hacerlo, conviene preguntarse:

  • ¿es realmente un error?
  • ¿es una categoría válida?
  • ¿afecta el análisis?
  • ¿conviene eliminar o recodificar?

Missing: qué son

Los missing son valores faltantes.

En R, normalmente se representan como:

NA
[1] NA

Detectar missing en una variable

is.na(Base$monto_texto)
[1] FALSE FALSE FALSE FALSE  TRUE FALSE
#Devuelve TRUE cuando falta el dato y FALSE cuando sí existe
sum(is.na(Base$monto_texto))
[1] 1
#Cuenta cuántos valores perdidos hay en la variable

Detectar missing por variable

colSums(is.na(Base))
           id        comuna        region   monto_texto         fecha 
            0             0             0             1             0 
         sexo          edad         tramo observaciones 
            0             0             0             0 
#Te resume cuantos NA hay en todas las columnas

Eliminar observaciones con missing

Base |>
  filter(!is.na(monto_texto))
# A tibble: 5 × 9
     id comuna         region  monto_texto fecha sexo   edad tramo observaciones
  <dbl> <chr>          <chr>   <chr>       <chr> <chr> <dbl> <chr> <chr>        
1     1 "Temuco "      La Ara… 120000      01-0… M        23 Acti… ok           
2     2 "temuco"       La Ara… Sin dato    02-0… F        35 Acti… revisar      
3     3 "P. Las Casas" La Ara… 540000      03-0… No r…    17 Sin … ok           
4     3 "P. Las Casas" La Ara… 540000      03-0… No r…    17 Sin … duplicado    
5     5 "Temuco"       Los Rí… 300000      06-0… M        29 Acti… otra región  
# Excluye todas las observaciones que estén vacías o con NA.
# Se necesita el paquete dplyr

Convertir respuestas específicas en NA

Base <- Base |>
  mutate(monto_texto = na_if(monto_texto, "Sin dato"))

#Reemplaza Siin dato por NA
#paquete dplyr

Base
# A tibble: 6 × 9
     id comuna         region  monto_texto fecha sexo   edad tramo observaciones
  <dbl> <chr>          <chr>   <chr>       <chr> <chr> <dbl> <chr> <chr>        
1     1 "Temuco "      La Ara… 120000      01-0… M        23 Acti… ok           
2     2 "temuco"       La Ara… <NA>        02-0… F        35 Acti… revisar      
3     3 "P. Las Casas" La Ara… 540000      03-0… No r…    17 Sin … ok           
4     3 "P. Las Casas" La Ara… 540000      03-0… No r…    17 Sin … duplicado    
5     4 "Villarrica"   La Ara… <NA>        05-0… F        61 Acti… falta monto  
6     5 "Temuco"       Los Rí… 300000      06-0… M        29 Acti… otra región  

Otro ejemplo de na_if()

Base <- Base |>
  mutate(sexo = na_if(sexo, "No responde"))

Base
# A tibble: 6 × 9
     id comuna         region  monto_texto fecha sexo   edad tramo observaciones
  <dbl> <chr>          <chr>   <chr>       <chr> <chr> <dbl> <chr> <chr>        
1     1 "Temuco "      La Ara… 120000      01-0… M        23 Acti… ok           
2     2 "temuco"       La Ara… <NA>        02-0… F        35 Acti… revisar      
3     3 "P. Las Casas" La Ara… 540000      03-0… <NA>     17 Sin … ok           
4     3 "P. Las Casas" La Ara… 540000      03-0… <NA>     17 Sin … duplicado    
5     4 "Villarrica"   La Ara… <NA>        05-0… F        61 Acti… falta monto  
6     5 "Temuco"       Los Rí… 300000      06-0… M        29 Acti… otra región  

Tipos de variables

Los tipos más frecuentes son:

  • numéricas
  • carácter
  • lógicas
  • fechas
  • factores

Revisar tipo de una variable

class(Base$monto_texto)
[1] "character"
class(Base$fecha)
[1] "character"
class(Base$comuna)
[1] "character"

Revisar estructura completa

str(Base)
tibble [6 × 9] (S3: tbl_df/tbl/data.frame)
 $ id           : num [1:6] 1 2 3 3 4 5
 $ comuna       : chr [1:6] "Temuco " "temuco" "P. Las Casas" "P. Las Casas" ...
 $ region       : chr [1:6] "La Araucanía" "La Araucanía" "La Araucanía" "La Araucanía" ...
 $ monto_texto  : chr [1:6] "120000" NA "540000" "540000" ...
 $ fecha        : chr [1:6] "01-04-2026" "02-04-2026" "03-04-2026" "03-04-2026" ...
 $ sexo         : chr [1:6] "M" "F" NA NA ...
 $ edad         : num [1:6] 23 35 17 17 61 29
 $ tramo        : chr [1:6] "Activo" "Activo" "Sin información" "Sin información" ...
 $ observaciones: chr [1:6] "ok" "revisar" "ok" "duplicado" ...

Convertir una variable a numérica

Base <- Base |>
  mutate(monto = as.numeric(monto_texto))

str(Base)
tibble [6 × 10] (S3: tbl_df/tbl/data.frame)
 $ id           : num [1:6] 1 2 3 3 4 5
 $ comuna       : chr [1:6] "Temuco " "temuco" "P. Las Casas" "P. Las Casas" ...
 $ region       : chr [1:6] "La Araucanía" "La Araucanía" "La Araucanía" "La Araucanía" ...
 $ monto_texto  : chr [1:6] "120000" NA "540000" "540000" ...
 $ fecha        : chr [1:6] "01-04-2026" "02-04-2026" "03-04-2026" "03-04-2026" ...
 $ sexo         : chr [1:6] "M" "F" NA NA ...
 $ edad         : num [1:6] 23 35 17 17 61 29
 $ tramo        : chr [1:6] "Activo" "Activo" "Sin información" "Sin información" ...
 $ observaciones: chr [1:6] "ok" "revisar" "ok" "duplicado" ...
 $ monto        : num [1:6] 120000 NA 540000 540000 NA 300000

Convertir una variable a carácter

Base <- Base |>
  mutate(comuna = as.character(comuna))

class(Base$comuna)
[1] "character"

Convertir una variable a factor

Base <- Base |>
  mutate(region = as.factor(region))

class(Base$region)
[1] "factor"

Convertir fechas

Base <- Base |>
  mutate(fecha = dmy(fecha))

class(Base$fecha)
[1] "Date"

Duplicados

Un duplicado ocurre cuando una observación aparece repetida.

Eso puede afectar:

  • conteos
  • promedios
  • porcentajes
  • totales

Detectar duplicados con una variable ID

Base |>
  get_dupes(id)
# A tibble: 2 × 11
     id dupe_count comuna       region  monto_texto fecha      sexo   edad tramo
  <dbl>      <int> <chr>        <fct>   <chr>       <date>     <chr> <dbl> <chr>
1     3          2 P. Las Casas La Ara… 540000      2026-04-03 <NA>     17 Sin …
2     3          2 P. Las Casas La Ara… 540000      2026-04-03 <NA>     17 Sin …
# ℹ 2 more variables: observaciones <chr>, monto <dbl>

Contar filas duplicadas

Base |>
  duplicated() |>
  sum()
[1] 0

Eliminar duplicados

Base_sin_duplicados <- Base |>
  distinct()

Base_sin_duplicados
# A tibble: 6 × 10
     id comuna     region monto_texto fecha      sexo   edad tramo observaciones
  <dbl> <chr>      <fct>  <chr>       <date>     <chr> <dbl> <chr> <chr>        
1     1 "Temuco "  La Ar… 120000      2026-04-01 M        23 Acti… ok           
2     2 "temuco"   La Ar… <NA>        2026-04-02 F        35 Acti… revisar      
3     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … ok           
4     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … duplicado    
5     4 "Villarri… La Ar… <NA>        2026-04-05 F        61 Acti… falta monto  
6     5 "Temuco"   Los R… 300000      2026-04-06 M        29 Acti… otra región  
# ℹ 1 more variable: monto <dbl>

Eliminar duplicados según un ID

Base_id_unico <- Base |>
  distinct(id, .keep_all = TRUE)

Base_id_unico
# A tibble: 5 × 10
     id comuna     region monto_texto fecha      sexo   edad tramo observaciones
  <dbl> <chr>      <fct>  <chr>       <date>     <chr> <dbl> <chr> <chr>        
1     1 "Temuco "  La Ar… 120000      2026-04-01 M        23 Acti… ok           
2     2 "temuco"   La Ar… <NA>        2026-04-02 F        35 Acti… revisar      
3     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … ok           
4     4 "Villarri… La Ar… <NA>        2026-04-05 F        61 Acti… falta monto  
5     5 "Temuco"   Los R… 300000      2026-04-06 M        29 Acti… otra región  
# ℹ 1 more variable: monto <dbl>

Recodificar una variable

Recodificar significa cambiar valores por otros.

Por ejemplo:

  • unificar etiquetas
  • simplificar respuestas
  • agrupar categorías
  • transformar códigos en nombres

Recodificar con recode()

Base <- Base |>
  mutate(
    sexo = recode(sexo,
                  "M" = "Masculino",
                  "F" = "Femenino")
  )

Base
# A tibble: 6 × 10
     id comuna     region monto_texto fecha      sexo   edad tramo observaciones
  <dbl> <chr>      <fct>  <chr>       <date>     <chr> <dbl> <chr> <chr>        
1     1 "Temuco "  La Ar… 120000      2026-04-01 Masc…    23 Acti… ok           
2     2 "temuco"   La Ar… <NA>        2026-04-02 Feme…    35 Acti… revisar      
3     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … ok           
4     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … duplicado    
5     4 "Villarri… La Ar… <NA>        2026-04-05 Feme…    61 Acti… falta monto  
6     5 "Temuco"   Los R… 300000      2026-04-06 Masc…    29 Acti… otra región  
# ℹ 1 more variable: monto <dbl>

Generar categorías con case_when()

Base <- Base |>
  mutate(
    tramo_edad = case_when(
      edad <= 17 ~ "0-17",
      edad >= 18 & edad <= 29 ~ "18-29",
      edad >= 30 & edad <= 59 ~ "30-59",
      edad >= 60 ~ "60 o más",
      TRUE ~ NA_character_
    )
  )

Base
# A tibble: 6 × 11
     id comuna     region monto_texto fecha      sexo   edad tramo observaciones
  <dbl> <chr>      <fct>  <chr>       <date>     <chr> <dbl> <chr> <chr>        
1     1 "Temuco "  La Ar… 120000      2026-04-01 Masc…    23 Acti… ok           
2     2 "temuco"   La Ar… <NA>        2026-04-02 Feme…    35 Acti… revisar      
3     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … ok           
4     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … duplicado    
5     4 "Villarri… La Ar… <NA>        2026-04-05 Feme…    61 Acti… falta monto  
6     5 "Temuco"   Los R… 300000      2026-04-06 Masc…    29 Acti… otra región  
# ℹ 2 more variables: monto <dbl>, tramo_edad <chr>

Generar categorías a partir de montos

Base <- Base |>
  mutate(
    tramo_monto = case_when(
      monto < 100000 ~ "Bajo",
      monto >= 100000 & monto < 500000 ~ "Medio",
      monto >= 500000 ~ "Alto",
      TRUE ~ NA_character_
    )
  )

Base
# A tibble: 6 × 12
     id comuna     region monto_texto fecha      sexo   edad tramo observaciones
  <dbl> <chr>      <fct>  <chr>       <date>     <chr> <dbl> <chr> <chr>        
1     1 "Temuco "  La Ar… 120000      2026-04-01 Masc…    23 Acti… ok           
2     2 "temuco"   La Ar… <NA>        2026-04-02 Feme…    35 Acti… revisar      
3     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … ok           
4     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … duplicado    
5     4 "Villarri… La Ar… <NA>        2026-04-05 Feme…    61 Acti… falta monto  
6     5 "Temuco"   Los R… 300000      2026-04-06 Masc…    29 Acti… otra región  
# ℹ 3 more variables: monto <dbl>, tramo_edad <chr>, tramo_monto <chr>

Crear una variable dicotómica

Base <- Base |>
  mutate(
    gasto_alto = if_else(monto >= 500000, 1, 0, missing = NA_real_)
  )

Base
# A tibble: 6 × 13
     id comuna     region monto_texto fecha      sexo   edad tramo observaciones
  <dbl> <chr>      <fct>  <chr>       <date>     <chr> <dbl> <chr> <chr>        
1     1 "Temuco "  La Ar… 120000      2026-04-01 Masc…    23 Acti… ok           
2     2 "temuco"   La Ar… <NA>        2026-04-02 Feme…    35 Acti… revisar      
3     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … ok           
4     3 "P. Las C… La Ar… 540000      2026-04-03 <NA>     17 Sin … duplicado    
5     4 "Villarri… La Ar… <NA>        2026-04-05 Feme…    61 Acti… falta monto  
6     5 "Temuco"   Los R… 300000      2026-04-06 Masc…    29 Acti… otra región  
# ℹ 4 more variables: monto <dbl>, tramo_edad <chr>, tramo_monto <chr>,
#   gasto_alto <dbl>

Corregir respuestas puntuales

Base <- Base |>
  mutate(
    comuna = if_else(comuna == "P. Las Casas",
                     "Padre Las Casas",
                     comuna)
  )

Base
# A tibble: 6 × 13
     id comuna     region monto_texto fecha      sexo   edad tramo observaciones
  <dbl> <chr>      <fct>  <chr>       <date>     <chr> <dbl> <chr> <chr>        
1     1 "Temuco "  La Ar… 120000      2026-04-01 Masc…    23 Acti… ok           
2     2 "temuco"   La Ar… <NA>        2026-04-02 Feme…    35 Acti… revisar      
3     3 "Padre La… La Ar… 540000      2026-04-03 <NA>     17 Sin … ok           
4     3 "Padre La… La Ar… 540000      2026-04-03 <NA>     17 Sin … duplicado    
5     4 "Villarri… La Ar… <NA>        2026-04-05 Feme…    61 Acti… falta monto  
6     5 "Temuco"   Los R… 300000      2026-04-06 Masc…    29 Acti… otra región  
# ℹ 4 more variables: monto <dbl>, tramo_edad <chr>, tramo_monto <chr>,
#   gasto_alto <dbl>

Unificar escritura de categorías

Base <- Base |>
  mutate(
    comuna = str_trim(comuna),
    comuna = str_to_title(comuna)
  )

Base
# A tibble: 6 × 13
     id comuna     region monto_texto fecha      sexo   edad tramo observaciones
  <dbl> <chr>      <fct>  <chr>       <date>     <chr> <dbl> <chr> <chr>        
1     1 Temuco     La Ar… 120000      2026-04-01 Masc…    23 Acti… ok           
2     2 Temuco     La Ar… <NA>        2026-04-02 Feme…    35 Acti… revisar      
3     3 Padre Las… La Ar… 540000      2026-04-03 <NA>     17 Sin … ok           
4     3 Padre Las… La Ar… 540000      2026-04-03 <NA>     17 Sin … duplicado    
5     4 Villarrica La Ar… <NA>        2026-04-05 Feme…    61 Acti… falta monto  
6     5 Temuco     Los R… 300000      2026-04-06 Masc…    29 Acti… otra región  
# ℹ 4 more variables: monto <dbl>, tramo_edad <chr>, tramo_monto <chr>,
#   gasto_alto <dbl>

Ordenar categorías

Base <- Base |>
  mutate(
    tramo_edad = factor(
      tramo_edad,
      levels = c("0-17", "18-29", "30-59", "60 o más")
    )
  )

levels(Base$tramo_edad)
[1] "0-17"     "18-29"    "30-59"    "60 o más"

Ejemplo integrado

Base_limpia <- Base |>
  clean_names() |>
  rename(
    comuna_limpia = comuna,
    monto_final = monto
  ) |>
  mutate(
    comuna_limpia = str_trim(comuna_limpia),
    comuna_limpia = str_to_title(comuna_limpia),
    tramo_monto_final = case_when(
      monto_final < 100000 ~ "Bajo",
      monto_final < 500000 ~ "Medio",
      monto_final >= 500000 ~ "Alto",
      TRUE ~ NA_character_
    )
  ) |>
  filter(!is.na(monto_final)) |>
  distinct()

Base_limpia
# A tibble: 4 × 14
     id comuna_limpia   region       monto_texto fecha      sexo      edad tramo
  <dbl> <chr>           <fct>        <chr>       <date>     <chr>    <dbl> <chr>
1     1 Temuco          La Araucanía 120000      2026-04-01 Masculi…    23 Acti…
2     3 Padre Las Casas La Araucanía 540000      2026-04-03 <NA>        17 Sin …
3     3 Padre Las Casas La Araucanía 540000      2026-04-03 <NA>        17 Sin …
4     5 Temuco          Los Ríos     300000      2026-04-06 Masculi…    29 Acti…
# ℹ 6 more variables: observaciones <chr>, monto_final <dbl>, tramo_edad <fct>,
#   tramo_monto <chr>, gasto_alto <dbl>, tramo_monto_final <chr>

¿Qué debemos registrar al limpiar?

Cada proceso de limpieza debiese dejar registro de:

  • problema detectado
  • cambio realizado
  • justificación del cambio
  • posible efecto sobre el análisis

Qué no conviene hacer

  • borrar datos sin justificar
  • cambiar categorías sin criterio
  • recodificar sin revisar la base
  • trabajar sin dejar trazabilidad
  • asumir que limpiar es una tarea menor

Resumen conceptual

En esta clase vimos que gestionar una base de datos implica:

  • revisar estructura
  • detectar errores
  • corregir variables
  • filtrar observaciones
  • recodificar respuestas
  • generar nuevas categorías
  • dejar la base en condiciones para analizar

Resumen de comandos clave

# eliminar objeto
rm(Base)

# renombrar objeto
base_nueva <- Base
rm(Base)

# renombrar variable
Base <- Base |> rename(comuna = nombre_comuna)

# eliminar variable
Base <- Base |> select(-comentarios)

# seleccionar variables
Base <- Base |> select(comuna, region, monto)

# eliminar observaciones
Base <- Base |> filter(region == "La Araucanía")

# eliminar una categoría específica
Base <- Base |> filter(sexo != "No responde")

# convertir texto específico en NA
Base <- Base |> mutate(sexo = na_if(sexo, "No responde"))

# recodificar
Base <- Base |> mutate(
  sexo = recode(sexo, "M" = "Masculino", "F" = "Femenino")
)

# generar categorías
Base <- Base |> mutate(
  tramo_edad = case_when(
    edad <= 17 ~ "0-17",
    edad <= 29 ~ "18-29",
    edad <= 59 ~ "30-59",
    edad >= 60 ~ "60 o más",
    TRUE ~ NA_character_
  )
)

Preguntas de cierre

  • ¿Qué diferencia hay entre limpiar y analizar?
  • ¿Cuándo conviene eliminar una observación?
  • ¿Cuándo conviene recodificar en vez de borrar?
  • ¿Por qué importa revisar el tipo de variable?
  • ¿Qué significa que una base esté ordenada?

Puente con la hora mixta

En el laboratorio aplicaremos estas operaciones sobre una base municipal, trabajando especialmente en:

  • nombres de variables
  • tipos de datos
  • montos
  • fechas
  • missing