Semana 06 - Limpieza y Transformación de Datos

Author

Johamnely Mateo

Published

June 14, 2026

Introducción

En esta práctica se realiza un proceso completo de limpieza, transformación y análisis de datos utilizando herramientas del ecosistema Tidyverse, especialmente el paquete dplyr.

El objetivo principal es trabajar con un dataset que contiene problemas reales como valores faltantes, registros duplicados, inconsistencias en texto y valores atípicos. Posteriormente se realizan transformaciones y un resumen analítico para validar la correcta integración de los datos.

Librerías

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.2.1     ✔ readr     2.2.0
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.3     ✔ tibble    3.3.1
✔ lubridate 1.9.5     ✔ tidyr     1.3.2
✔ purrr     1.2.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)
library(stringr)
library(tidyr)
library(knitr)

Parte 1 - Creación del Dataset

Se crea un tibble con información de ventas que contiene distintos problemas de calidad de datos.

ventas_crudas <- tibble(
  id_venta = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 3),

  vendedor = c(
    "ana", "PEDRO", "María ", NA,
    "carmen", "ana", "PEDRO",
    "luis", "carmen", "luis",
    "María "
  ),

  region = c(
    "norte", "SUR", "Norte",
    "sur", "NORTE", "norte",
    "sur", "Norte", "sur",
    "norte", "Norte"
  ),

  monto = c(
    15000, 22000, 18500,
    NA, 31000, 16000,
    19500, 9500000,
    21000, 17500, 18500
  ),

  mes = c(
    1, 1, 1, 2, 2,
    2, 3, 3, 3, 3, 1
  ),

  completada = c(
    "SI", "SI", "NO",
    "SI", NA, "SI",
    "NO", "SI", "SI",
    "NO", "NO"
  )
)

ventas_crudas
# A tibble: 11 × 6
   id_venta vendedor region   monto   mes completada
      <dbl> <chr>    <chr>    <dbl> <dbl> <chr>     
 1        1 "ana"    norte    15000     1 SI        
 2        2 "PEDRO"  SUR      22000     1 SI        
 3        3 "María " Norte    18500     1 NO        
 4        4  <NA>    sur         NA     2 SI        
 5        5 "carmen" NORTE    31000     2 <NA>      
 6        6 "ana"    norte    16000     2 SI        
 7        7 "PEDRO"  sur      19500     3 NO        
 8        8 "luis"   Norte  9500000     3 SI        
 9        9 "carmen" sur      21000     3 SI        
10       10 "luis"   norte    17500     3 NO        
11        3 "María " Norte    18500     1 NO        

Parte 2 - Diagnóstico Inicial

Visualización general del dataset

glimpse(ventas_crudas)
Rows: 11
Columns: 6
$ id_venta   <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 3
$ vendedor   <chr> "ana", "PEDRO", "María ", NA, "carmen", "ana", "PEDRO", "lu…
$ region     <chr> "norte", "SUR", "Norte", "sur", "NORTE", "norte", "sur", "N…
$ monto      <dbl> 15000, 22000, 18500, NA, 31000, 16000, 19500, 9500000, 2100…
$ mes        <dbl> 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 1
$ completada <chr> "SI", "SI", "NO", "SI", NA, "SI", "NO", "SI", "SI", "NO", "…

Resumen estadístico

summary(ventas_crudas)
    id_venta           vendedor        region       monto              mes   
 Min.   : 1.000   Length   :11   Length   :11   Min.   :  15000   Min.   :1  
 1st Qu.: 3.000   N.unique : 5   N.unique : 5   1st Qu.:  17750   1st Qu.:1  
 Median : 5.000   N.blank  : 0   N.blank  : 0   Median :  19000   Median :2  
 Mean   : 5.273   Min.nchar: 3   Min.nchar: 3   Mean   : 967900   Mean   :2  
 3rd Qu.: 7.500   Max.nchar: 6   Max.nchar: 5   3rd Qu.:  21750   3rd Qu.:3  
 Max.   :10.000   NAs      : 1                  Max.   :9500000   Max.   :3  
                                                NAs    :1                    
     completada
 Length   :11  
 N.unique : 2  
 N.blank  : 0  
 Min.nchar: 2  
 Max.nchar: 2  
 NAs      : 1  
               

Conteo de valores faltantes

colSums(is.na(ventas_crudas))
  id_venta   vendedor     region      monto        mes completada 
         0          1          0          1          0          1 

Identificación de registros duplicados

duplicados <- ventas_crudas %>%
  count(id_venta) %>%
  filter(n > 1)

duplicados
# A tibble: 1 × 2
  id_venta     n
     <dbl> <int>
1        3     2

Identificación del valor máximo

max(ventas_crudas$monto, na.rm = TRUE)
[1] 9500000

Parte 3 - Limpieza de Datos

Eliminación de duplicados

ventas_limpias <- ventas_crudas %>%
  distinct(id_venta, .keep_all = TRUE)

ventas_limpias
# A tibble: 10 × 6
   id_venta vendedor region   monto   mes completada
      <dbl> <chr>    <chr>    <dbl> <dbl> <chr>     
 1        1 "ana"    norte    15000     1 SI        
 2        2 "PEDRO"  SUR      22000     1 SI        
 3        3 "María " Norte    18500     1 NO        
 4        4  <NA>    sur         NA     2 SI        
 5        5 "carmen" NORTE    31000     2 <NA>      
 6        6 "ana"    norte    16000     2 SI        
 7        7 "PEDRO"  sur      19500     3 NO        
 8        8 "luis"   Norte  9500000     3 SI        
 9        9 "carmen" sur      21000     3 SI        
10       10 "luis"   norte    17500     3 NO        

Limpieza de texto

Se corrigen espacios innecesarios y formatos inconsistentes en las columnas de texto.

ventas_limpias <- ventas_limpias %>%
  mutate(
    vendedor = str_trim(vendedor),
    vendedor = str_to_title(vendedor),

    region = str_trim(region),
    region = str_to_lower(region)
  )

ventas_limpias
# A tibble: 10 × 6
   id_venta vendedor region   monto   mes completada
      <dbl> <chr>    <chr>    <dbl> <dbl> <chr>     
 1        1 Ana      norte    15000     1 SI        
 2        2 Pedro    sur      22000     1 SI        
 3        3 María    norte    18500     1 NO        
 4        4 <NA>     sur         NA     2 SI        
 5        5 Carmen   norte    31000     2 <NA>      
 6        6 Ana      norte    16000     2 SI        
 7        7 Pedro    sur      19500     3 NO        
 8        8 Luis     norte  9500000     3 SI        
 9        9 Carmen   sur      21000     3 SI        
10       10 Luis     norte    17500     3 NO        

Imputación del vendedor faltante

ventas_limpias <- ventas_limpias %>%
  mutate(
    vendedor = replace_na(vendedor, "Desconocido")
  )

ventas_limpias
# A tibble: 10 × 6
   id_venta vendedor    region   monto   mes completada
      <dbl> <chr>       <chr>    <dbl> <dbl> <chr>     
 1        1 Ana         norte    15000     1 SI        
 2        2 Pedro       sur      22000     1 SI        
 3        3 María       norte    18500     1 NO        
 4        4 Desconocido sur         NA     2 SI        
 5        5 Carmen      norte    31000     2 <NA>      
 6        6 Ana         norte    16000     2 SI        
 7        7 Pedro       sur      19500     3 NO        
 8        8 Luis        norte  9500000     3 SI        
 9        9 Carmen      sur      21000     3 SI        
10       10 Luis        norte    17500     3 NO        

Imputación del monto utilizando la mediana del mes

ventas_limpias <- ventas_limpias %>%
  group_by(mes) %>%
  mutate(
    monto = ifelse(
      is.na(monto),
      median(monto, na.rm = TRUE),
      monto
    )
  ) %>%
  ungroup()

ventas_limpias
# A tibble: 10 × 6
   id_venta vendedor    region   monto   mes completada
      <dbl> <chr>       <chr>    <dbl> <dbl> <chr>     
 1        1 Ana         norte    15000     1 SI        
 2        2 Pedro       sur      22000     1 SI        
 3        3 María       norte    18500     1 NO        
 4        4 Desconocido sur      23500     2 SI        
 5        5 Carmen      norte    31000     2 <NA>      
 6        6 Ana         norte    16000     2 SI        
 7        7 Pedro       sur      19500     3 NO        
 8        8 Luis        norte  9500000     3 SI        
 9        9 Carmen      sur      21000     3 SI        
10       10 Luis        norte    17500     3 NO        

Conversión de completada a factor

ventas_limpias <- ventas_limpias %>%
  mutate(
    completada = replace_na(completada, "NO"),
    completada = factor(completada)
  )

ventas_limpias
# A tibble: 10 × 6
   id_venta vendedor    region   monto   mes completada
      <dbl> <chr>       <chr>    <dbl> <dbl> <fct>     
 1        1 Ana         norte    15000     1 SI        
 2        2 Pedro       sur      22000     1 SI        
 3        3 María       norte    18500     1 NO        
 4        4 Desconocido sur      23500     2 SI        
 5        5 Carmen      norte    31000     2 NO        
 6        6 Ana         norte    16000     2 SI        
 7        7 Pedro       sur      19500     3 NO        
 8        8 Luis        norte  9500000     3 SI        
 9        9 Carmen      sur      21000     3 SI        
10       10 Luis        norte    17500     3 NO        

Detección de outliers con IQR

Q1 <- quantile(ventas_limpias$monto, 0.25)

Q3 <- quantile(ventas_limpias$monto, 0.75)

IQR_valor <- IQR(ventas_limpias$monto)

limite_inferior <- Q1 - 1.5 * IQR_valor

limite_superior <- Q3 + 1.5 * IQR_valor

ventas_limpias <- ventas_limpias %>%
  mutate(
    es_outlier = monto < limite_inferior |
                 monto > limite_superior
  )

ventas_limpias
# A tibble: 10 × 7
   id_venta vendedor    region   monto   mes completada es_outlier
      <dbl> <chr>       <chr>    <dbl> <dbl> <fct>      <lgl>     
 1        1 Ana         norte    15000     1 SI         FALSE     
 2        2 Pedro       sur      22000     1 SI         FALSE     
 3        3 María       norte    18500     1 NO         FALSE     
 4        4 Desconocido sur      23500     2 SI         FALSE     
 5        5 Carmen      norte    31000     2 NO         FALSE     
 6        6 Ana         norte    16000     2 SI         FALSE     
 7        7 Pedro       sur      19500     3 NO         FALSE     
 8        8 Luis        norte  9500000     3 SI         TRUE      
 9        9 Carmen      sur      21000     3 SI         FALSE     
10       10 Luis        norte    17500     3 NO         FALSE     

Parte 4 - Transformación con dplyr

Creación de la columna comisión

ventas_limpias <- ventas_limpias %>%
  mutate(
    comision = ifelse(
      completada == "SI",
      monto * 0.05,
      0
    )
  )

ventas_limpias
# A tibble: 10 × 8
   id_venta vendedor    region   monto   mes completada es_outlier comision
      <dbl> <chr>       <chr>    <dbl> <dbl> <fct>      <lgl>         <dbl>
 1        1 Ana         norte    15000     1 SI         FALSE           750
 2        2 Pedro       sur      22000     1 SI         FALSE          1100
 3        3 María       norte    18500     1 NO         FALSE             0
 4        4 Desconocido sur      23500     2 SI         FALSE          1175
 5        5 Carmen      norte    31000     2 NO         FALSE             0
 6        6 Ana         norte    16000     2 SI         FALSE           800
 7        7 Pedro       sur      19500     3 NO         FALSE             0
 8        8 Luis        norte  9500000     3 SI         TRUE         475000
 9        9 Carmen      sur      21000     3 SI         FALSE          1050
10       10 Luis        norte    17500     3 NO         FALSE             0

Creación de categoría de venta

ventas_limpias <- ventas_limpias %>%
  mutate(
    categoria_venta = case_when(
      monto < 15000 ~ "Baja",
      monto >= 15000 & monto <= 25000 ~ "Media",
      monto > 25000 ~ "Alta"
    )
  )

ventas_limpias
# A tibble: 10 × 9
   id_venta vendedor    region   monto   mes completada es_outlier comision
      <dbl> <chr>       <chr>    <dbl> <dbl> <fct>      <lgl>         <dbl>
 1        1 Ana         norte    15000     1 SI         FALSE           750
 2        2 Pedro       sur      22000     1 SI         FALSE          1100
 3        3 María       norte    18500     1 NO         FALSE             0
 4        4 Desconocido sur      23500     2 SI         FALSE          1175
 5        5 Carmen      norte    31000     2 NO         FALSE             0
 6        6 Ana         norte    16000     2 SI         FALSE           800
 7        7 Pedro       sur      19500     3 NO         FALSE             0
 8        8 Luis        norte  9500000     3 SI         TRUE         475000
 9        9 Carmen      sur      21000     3 SI         FALSE          1050
10       10 Luis        norte    17500     3 NO         FALSE             0
# ℹ 1 more variable: categoria_venta <chr>

Ranking de vendedores por región

ventas_limpias <- ventas_limpias %>%
  group_by(region) %>%
  mutate(
    ranking_region = rank(desc(monto))
  ) %>%
  ungroup()

ventas_limpias
# A tibble: 10 × 10
   id_venta vendedor    region   monto   mes completada es_outlier comision
      <dbl> <chr>       <chr>    <dbl> <dbl> <fct>      <lgl>         <dbl>
 1        1 Ana         norte    15000     1 SI         FALSE           750
 2        2 Pedro       sur      22000     1 SI         FALSE          1100
 3        3 María       norte    18500     1 NO         FALSE             0
 4        4 Desconocido sur      23500     2 SI         FALSE          1175
 5        5 Carmen      norte    31000     2 NO         FALSE             0
 6        6 Ana         norte    16000     2 SI         FALSE           800
 7        7 Pedro       sur      19500     3 NO         FALSE             0
 8        8 Luis        norte  9500000     3 SI         TRUE         475000
 9        9 Carmen      sur      21000     3 SI         FALSE          1050
10       10 Luis        norte    17500     3 NO         FALSE             0
# ℹ 2 more variables: categoria_venta <chr>, ranking_region <dbl>

Dataset Final Limpio

knitr::kable(
  ventas_limpias,
  caption = "Dataset Final Limpio"
)
Dataset Final Limpio
id_venta vendedor region monto mes completada es_outlier comision categoria_venta ranking_region
1 Ana norte 15000 1 SI FALSE 750 Media 6
2 Pedro sur 22000 1 SI FALSE 1100 Media 2
3 María norte 18500 1 NO FALSE 0 Media 3
4 Desconocido sur 23500 2 SI FALSE 1175 Media 1
5 Carmen norte 31000 2 NO FALSE 0 Alta 2
6 Ana norte 16000 2 SI FALSE 800 Media 5
7 Pedro sur 19500 3 NO FALSE 0 Media 4
8 Luis norte 9500000 3 SI TRUE 475000 Alta 1
9 Carmen sur 21000 3 SI FALSE 1050 Media 3
10 Luis norte 17500 3 NO FALSE 0 Media 4

Parte 5 - Resumen Analítico

Tabla resumen por vendedor

resumen_ventas <- ventas_limpias %>%
  group_by(vendedor) %>%
  summarise(

    total_ventas_completadas =
      sum(completada == "SI"),

    monto_total_vendido =
      sum(monto),

    monto_promedio_venta =
      mean(monto),

    comision_total_ganada =
      sum(comision)

  ) %>%
  arrange(desc(monto_total_vendido))

resumen_ventas
# A tibble: 6 × 5
  vendedor    total_ventas_completadas monto_total_vendido monto_promedio_venta
  <chr>                          <int>               <dbl>                <dbl>
1 Luis                               1             9517500              4758750
2 Carmen                             1               52000                26000
3 Pedro                              1               41500                20750
4 Ana                                2               31000                15500
5 Desconocido                        1               23500                23500
6 María                              0               18500                18500
# ℹ 1 more variable: comision_total_ganada <dbl>

Tabla Final Analítica

knitr::kable(
  resumen_ventas,
  digits = 2,
  caption = "Resumen Analítico de Ventas por Vendedor"
)
Resumen Analítico de Ventas por Vendedor
vendedor total_ventas_completadas monto_total_vendido monto_promedio_venta comision_total_ganada
Luis 1 9517500 4758750 475000
Carmen 1 52000 26000 1050
Pedro 1 41500 20750 1100
Ana 2 31000 15500 1550
Desconocido 1 23500 23500 1175
María 0 18500 18500 0

Conclusión

Durante esta práctica se trabajó un proceso completo de limpieza y transformación de datos utilizando herramientas del ecosistema Tidyverse y especialmente el paquete dplyr.

Se realizaron tareas de diagnóstico inicial, eliminación de duplicados, corrección de formatos de texto, imputación de valores faltantes, detección de outliers y creación de nuevas variables analíticas.

Finalmente, se construyó un resumen estadístico por vendedor que permitió validar la correcta integración y transformación de los datos.