Semana 05 — Importación de Datos desde Múltiples Fuentes

Author

Jogeysi Carrasco

Published

June 28, 2026

1 Parte 1 — Leer el CSV

En esta sección leemos el archivo empleados.csv especificando los tipos de columnas manualmente con el argumento col_types de read_csv(). Es fundamental controlar los tipos de datos desde la lectura para evitar conversiones implícitas que pueden introducir errores silenciosos.

Code
library(tidyverse)

# Leer CSV con tipos de columnas especificados manualmente
empleados <- read_csv(
  "empleados.csv",
  col_types = cols(
    id_empleado     = col_character(),   # ID como cadena para preservar ceros iniciales
    nombre          = col_character(),
    departamento    = col_character(),
    salario_mensual = col_double(),
    fecha_ingreso   = col_date(format = "%Y-%m-%d")
  )
)

# Verificar estructura y tipos
glimpse(empleados)
Rows: 20
Columns: 5
$ id_empleado     <chr> "001", "002", "003", "004", "005", "006", "007", "008"…
$ nombre          <chr> "Ana Torres", "Pedro Méndez", "María López", "Luis Gar…
$ departamento    <chr> "Tecnología", "Auditoría", "Tecnología", "RRHH", "Audi…
$ salario_mensual <dbl> 58000, 45000, 63000, 41000, 52000, 70000, 65000, 48000…
$ fecha_ingreso   <date> 2019-03-15, 2021-07-01, 2018-11-20, 2022-01-10, 2020-…

La función glimpse() confirma que:

  • id_empleado es <chr> — preserva los ceros iniciales ("001", "002", …)
  • fecha_ingreso es <date> — permite operaciones de fechas como difftime() o lubridate
  • salario_mensual es <dbl> — tipo numérico para cálculos
Code
# Vista rápida de los datos
empleados |>
  select(id_empleado, nombre, departamento, salario_mensual, fecha_ingreso) |>
  head(10) |>
  knitr::kable(caption = "Primeras 10 filas de empleados.csv")
Primeras 10 filas de empleados.csv
id_empleado nombre departamento salario_mensual fecha_ingreso
001 Ana Torres Tecnología 58000 2019-03-15
002 Pedro Méndez Auditoría 45000 2021-07-01
003 María López Tecnología 63000 2018-11-20
004 Luis García RRHH 41000 2022-01-10
005 Carmen Díaz Auditoría 52000 2020-05-30
006 Carlos Mendoza Tecnología 70000 2017-04-12
007 Elena Rostova Riesgo 65000 2021-09-18
008 Jorge Ortiz Finanzas 48000 2023-02-05
009 Lucía Blanco RRHH 39000 2022-11-11
010 Andrés Castro Riesgo 59000 2020-08-24

El dataset tiene 20 empleados distribuidos en 5 departamentos: Auditoría, Finanzas, Riesgo, RRHH, Tecnología.


2 Parte 2 — Leer el Excel

El archivo empleados.xlsx contiene dos hojas ("2022" y "2023") con registros de períodos distintos. Las leemos por separado con read_excel(), añadimos una columna anio que identifica el origen, y luego las combinamos con bind_rows().

Code
library(readxl)

# Leer cada sheet por separado y agregar columna de identificación
hoja_2022 <- read_excel("empleados.xlsx", sheet = "2022") |>
  mutate(anio = 2022L)

hoja_2023 <- read_excel("empleados.xlsx", sheet = "2023") |>
  mutate(anio = 2023L)

# Combinar en un único tibble
empleados_excel <- bind_rows(hoja_2022, hoja_2023)

glimpse(empleados_excel)
Rows: 25
Columns: 6
$ id_empleado     <chr> "001", "002", "003", "004", "005", "006", "007", "009"…
$ nombre          <chr> "Ana Torres", "Pedro Méndez", "María López", "Luis Gar…
$ departamento    <chr> "Tecnología", "Auditoría", "Tecnología", "RRHH", "Audi…
$ salario_mensual <dbl> 58000, 45000, 63000, 41000, 52000, 70000, 65000, 39000…
$ fecha_periodo   <chr> "2022-01-15", "2022-03-10", "2022-06-20", "2022-01-10"…
$ anio            <int> 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, …

El tibble combinado tiene 25 filas — 13 de 2022 y 12 de 2023.

2.1 Promedio de salario por departamento

Code
resumen_depto <- empleados_excel |>
  group_by(departamento, anio) |>
  summarise(
    n_empleados      = n(),
    salario_promedio = round(mean(salario_mensual, na.rm = TRUE), 0),
    .groups = "drop"
  ) |>
  arrange(departamento, anio)

resumen_depto |>
  knitr::kable(
    caption = "Tabla 2. Promedio de salario mensual por departamento y año",
    col.names = c("Departamento", "Año", "N° Empleados", "Salario Promedio (MXN)"),
    format.args = list(big.mark = ",")
  )
Tabla 2. Promedio de salario mensual por departamento y año
Departamento Año N° Empleados Salario Promedio (MXN)
Auditoría 2,022 3 48,000
Auditoría 2,023 1 51,000
Finanzas 2,022 1 46,000
Finanzas 2,023 2 51,500
RRHH 2,022 3 40,667
RRHH 2,023 1 40,000
Riesgo 2,022 2 62,000
Riesgo 2,023 3 66,333
Tecnología 2,022 4 61,500
Tecnología 2,023 5 67,400
Code
resumen_depto |>
  mutate(anio = factor(anio)) |>
  ggplot(aes(x = reorder(departamento, salario_promedio),
             y = salario_promedio,
             fill = anio)) +
  geom_col(position = "dodge", width = 0.65) +
  geom_text(aes(label = scales::comma(salario_promedio)),
            position = position_dodge(width = 0.65),
            hjust = -0.1, size = 3) +
  scale_fill_manual(values = c("2022" = "#2C5F8A", "2023" = "#1A9870")) +
  scale_y_continuous(labels = scales::comma, expand = expansion(mult = c(0, 0.2))) +
  coord_flip() +
  labs(
    title = "Salario promedio por departamento",
    subtitle = "Comparación 2022 vs 2023",
    x = NULL, y = "Salario mensual (MXN)", fill = "Año"
  ) +
  theme_minimal(base_size = 12) +
  theme(legend.position = "bottom",
        panel.grid.major.y = element_blank())


3 Parte 3 — Conectar a SQLite

En esta sección usamos el paquete DBI junto con RSQLite para:

  1. Abrir una conexión a la base de datos empresa.sqlite
  2. Crear la tabla empleados con dbWriteTable()
  3. Consultar los registros de 2023 con dbGetQuery() usando una cláusula WHERE
Code
library(DBI)
library(RSQLite)

# Conectar a la base SQLite (crea el archivo si no existe)
con <- dbConnect(RSQLite::SQLite(), dbname = "empresa.sqlite")

# Definir el tibble de datos a insertar
datos_sqlite <- tibble(
  id_empleado     = c("001","002","003","004","005","006","007","008","009","010",
                      "011","012","013","014","015","016","019","020",
                      "001","003","006","007","008","009","011","013",
                      "015","016","019","020"),
  anio            = c(rep(2022L, 18), rep(2023L, 12)),
  monto_total_ano = c(
    # 2022
    696000, 540000, 756000, 492000, 624000, 840000, 780000, 576000,
    468000, 708000, 768000, 564000, 660000, 660000, 804000, 612000,
    900000, 732000,
    # 2023
    720000, 780000, 876000, 816000, 576000, 480000, 768000, 660000,
    840000, 612000, 900000, 732000
  )
)

# Escribir la tabla en SQLite (sobreescribir si ya existe)
dbWriteTable(con, name = "empleados", value = datos_sqlite, overwrite = TRUE)

# Confirmar que la tabla fue creada
dbListTables(con)
[1] "empleados"
Code
# Consulta SQL con WHERE anio = 2023
resultado_2023 <- dbGetQuery(
  con,
  "SELECT id_empleado,
          anio,
          monto_total_ano,
          ROUND(monto_total_ano / 12.0, 0) AS promedio_mensual
   FROM   empleados
   WHERE  anio = 2023
   ORDER  BY monto_total_ano DESC"
)

resultado_2023 |>
  knitr::kable(
    caption  = "Tabla 3. Registros de la tabla SQLite 'empleados' filtrados por anio = 2023",
    col.names = c("ID Empleado", "Año", "Monto Total Año (MXN)", "Promedio Mensual (MXN)"),
    format.args = list(big.mark = ",")
  )
Tabla 3. Registros de la tabla SQLite ‘empleados’ filtrados por anio = 2023
ID Empleado Año Monto Total Año (MXN) Promedio Mensual (MXN)
019 2,023 900,000 75,000
006 2,023 876,000 73,000
015 2,023 840,000 70,000
007 2,023 816,000 68,000
003 2,023 780,000 65,000
011 2,023 768,000 64,000
020 2,023 732,000 61,000
001 2,023 720,000 60,000
013 2,023 660,000 55,000
016 2,023 612,000 51,000
008 2,023 576,000 48,000
009 2,023 480,000 40,000
Code
# Siempre cerrar la conexión al terminar
dbDisconnect(con)
cat("Conexión cerrada correctamente.\n")
Conexión cerrada correctamente.

La consulta devolvió 12 registros correspondientes al año 2023. El monto total anual más alto fue de 900,000 MXN y el más bajo de 480,000 MXN.


4 Resumen de la sesión

Fuente Función principal Paquete Registros leídos
empleados.csv read_csv() readr 20 filas
empleados.xlsx read_excel() readxl 25 filas (2 sheets)
empresa.sqlite dbGetQuery() DBI/RSQLite 12 filas (WHERE 2023)

Buena práctica: Siempre especifica col_types en read_csv(), lee cada sheet con su nombre explícito, y llama dbDisconnect() al finalizar cualquier sesión con una base de datos.