Parte 1: Preparación de los datos

# Lista de todos los paquetes que necesitas
paquetes <- c(
  "tidyverse", "lubridate", "janitor", "ggplot2", "plotly",
  "highcharter", "echarts4r", "leaflet", "sf", "skimr"
)

# Instala solo los que no tengas
instalados <- rownames(installed.packages())

for (p in paquetes) {
  if (!(p %in% instalados)) {
    install.packages(p)
  }
}

# Luego los cargas
lapply(paquetes, library, character.only = TRUE)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.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
## 
## Attaching package: 'janitor'
## 
## 
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
## 
## 
## 
## Attaching package: 'plotly'
## 
## 
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## 
## 
## The following object is masked from 'package:stats':
## 
##     filter
## 
## 
## The following object is masked from 'package:graphics':
## 
##     layout
## 
## 
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo 
## 
## Linking to GEOS 3.13.0, GDAL 3.8.5, PROJ 9.5.1; sf_use_s2() is TRUE
## [[1]]
##  [1] "lubridate" "forcats"   "stringr"   "dplyr"     "purrr"     "readr"    
##  [7] "tidyr"     "tibble"    "ggplot2"   "tidyverse" "stats"     "graphics" 
## [13] "grDevices" "utils"     "datasets"  "methods"   "base"     
## 
## [[2]]
##  [1] "lubridate" "forcats"   "stringr"   "dplyr"     "purrr"     "readr"    
##  [7] "tidyr"     "tibble"    "ggplot2"   "tidyverse" "stats"     "graphics" 
## [13] "grDevices" "utils"     "datasets"  "methods"   "base"     
## 
## [[3]]
##  [1] "janitor"   "lubridate" "forcats"   "stringr"   "dplyr"     "purrr"    
##  [7] "readr"     "tidyr"     "tibble"    "ggplot2"   "tidyverse" "stats"    
## [13] "graphics"  "grDevices" "utils"     "datasets"  "methods"   "base"     
## 
## [[4]]
##  [1] "janitor"   "lubridate" "forcats"   "stringr"   "dplyr"     "purrr"    
##  [7] "readr"     "tidyr"     "tibble"    "ggplot2"   "tidyverse" "stats"    
## [13] "graphics"  "grDevices" "utils"     "datasets"  "methods"   "base"     
## 
## [[5]]
##  [1] "plotly"    "janitor"   "lubridate" "forcats"   "stringr"   "dplyr"    
##  [7] "purrr"     "readr"     "tidyr"     "tibble"    "ggplot2"   "tidyverse"
## [13] "stats"     "graphics"  "grDevices" "utils"     "datasets"  "methods"  
## [19] "base"     
## 
## [[6]]
##  [1] "highcharter" "plotly"      "janitor"     "lubridate"   "forcats"    
##  [6] "stringr"     "dplyr"       "purrr"       "readr"       "tidyr"      
## [11] "tibble"      "ggplot2"     "tidyverse"   "stats"       "graphics"   
## [16] "grDevices"   "utils"       "datasets"    "methods"     "base"       
## 
## [[7]]
##  [1] "echarts4r"   "highcharter" "plotly"      "janitor"     "lubridate"  
##  [6] "forcats"     "stringr"     "dplyr"       "purrr"       "readr"      
## [11] "tidyr"       "tibble"      "ggplot2"     "tidyverse"   "stats"      
## [16] "graphics"    "grDevices"   "utils"       "datasets"    "methods"    
## [21] "base"       
## 
## [[8]]
##  [1] "leaflet"     "echarts4r"   "highcharter" "plotly"      "janitor"    
##  [6] "lubridate"   "forcats"     "stringr"     "dplyr"       "purrr"      
## [11] "readr"       "tidyr"       "tibble"      "ggplot2"     "tidyverse"  
## [16] "stats"       "graphics"    "grDevices"   "utils"       "datasets"   
## [21] "methods"     "base"       
## 
## [[9]]
##  [1] "sf"          "leaflet"     "echarts4r"   "highcharter" "plotly"     
##  [6] "janitor"     "lubridate"   "forcats"     "stringr"     "dplyr"      
## [11] "purrr"       "readr"       "tidyr"       "tibble"      "ggplot2"    
## [16] "tidyverse"   "stats"       "graphics"    "grDevices"   "utils"      
## [21] "datasets"    "methods"     "base"       
## 
## [[10]]
##  [1] "skimr"       "sf"          "leaflet"     "echarts4r"   "highcharter"
##  [6] "plotly"      "janitor"     "lubridate"   "forcats"     "stringr"    
## [11] "dplyr"       "purrr"       "readr"       "tidyr"       "tibble"     
## [16] "ggplot2"     "tidyverse"   "stats"       "graphics"    "grDevices"  
## [21] "utils"       "datasets"    "methods"     "base"

1. Leer todos los archivos CSV y unirlos en una sola tabla datos_completos.

campañas <- read_csv("marketing_campañas.csv") %>% clean_names()
## Rows: 300 Columns: 3
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): Nombre_Campaña, Departamento
## dbl (1): ID_Campaña
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
str(campañas)
## spc_tbl_ [300 × 3] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id_campana    : num [1:300] 1 2 3 4 5 6 7 8 9 10 ...
##  $ nombre_campana: chr [1:300] "Campaña_1" "Campaña_2" "Campaña_3" "Campaña_4" ...
##  $ departamento  : chr [1:300] "La Paz" "Pando" "Oruro" "Tarija" ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   ID_Campaña = col_double(),
##   ..   Nombre_Campaña = col_character(),
##   ..   Departamento = col_character()
##   .. )
##  - attr(*, "problems")=<externalptr>
clientes <- read_csv("marketing_clientes.csv") %>% clean_names()
## Rows: 1000 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (4): Nombre, Genero, Departamento, Ciudad
## dbl (2): ID_Cliente, Edad
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
str(clientes)
## spc_tbl_ [1,000 × 6] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id_cliente  : num [1:1000] 1 2 3 4 5 6 7 8 9 10 ...
##  $ nombre      : chr [1:1000] "Cliente_1" "Cliente_2" "Cliente_3" "Cliente_4" ...
##  $ edad        : num [1:1000] 56 46 32 60 25 38 56 36 40 28 ...
##  $ genero      : chr [1:1000] "Masculino" "Otro" "Otro" "Femenino" ...
##  $ departamento: chr [1:1000] "Chuquisaca" "Potosí" "Oruro" "Beni" ...
##  $ ciudad      : chr [1:1000] "Sucre" "Potosí" "Oruro" "Trinidad" ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   ID_Cliente = col_double(),
##   ..   Nombre = col_character(),
##   ..   Edad = col_double(),
##   ..   Genero = col_character(),
##   ..   Departamento = col_character(),
##   ..   Ciudad = col_character()
##   .. )
##  - attr(*, "problems")=<externalptr>
servicios <- read_csv("marketing_servicios.csv") %>% clean_names()
## Rows: 200 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): Nombre_Servicio, Categoría
## dbl (2): ID_Servicio, Precio_Unitario
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
str(servicios)
## spc_tbl_ [200 × 4] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id_servicio    : num [1:200] 1 2 3 4 5 6 7 8 9 10 ...
##  $ nombre_servicio: chr [1:200] "Email Marketing" "Contenido" "Contenido" "Publicidad" ...
##  $ categoria      : chr [1:200] "Creatividad" "Desarrollo Web" "Análisis de Datos" "Desarrollo Web" ...
##  $ precio_unitario: num [1:200] 712 1639 584 1395 1544 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   ID_Servicio = col_double(),
##   ..   Nombre_Servicio = col_character(),
##   ..   Categoría = col_character(),
##   ..   Precio_Unitario = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>
transacciones <- read_csv("marketing_transacciones.csv") %>% clean_names()
## Rows: 5000 Columns: 7
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl  (6): ID_Transaccion, ID_Cliente, ID_Servicio, ID_Campaña, Cantidad, Total
## date (1): Fecha
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
str(transacciones)
## spc_tbl_ [5,000 × 7] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ id_transaccion: num [1:5000] 1 2 3 4 5 6 7 8 9 10 ...
##  $ id_cliente    : num [1:5000] 450 892 276 888 30 534 814 711 831 777 ...
##  $ id_servicio   : num [1:5000] 29 156 192 56 78 21 74 97 160 38 ...
##  $ id_campana    : num [1:5000] 295 125 221 210 295 158 25 15 108 166 ...
##  $ cantidad      : num [1:5000] 5 2 7 4 5 9 5 4 8 8 ...
##  $ total         : num [1:5000] 3909 1922 12621 2769 3784 ...
##  $ fecha         : Date[1:5000], format: "2023-01-11" "2023-07-14" ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   ID_Transaccion = col_double(),
##   ..   ID_Cliente = col_double(),
##   ..   ID_Servicio = col_double(),
##   ..   ID_Campaña = col_double(),
##   ..   Cantidad = col_double(),
##   ..   Total = col_double(),
##   ..   Fecha = col_date(format = "")
##   .. )
##  - attr(*, "problems")=<externalptr>
departamentos_geo <- st_read("bolivia_departamentos_dos.geojson")
## Reading layer `bolivia_departamentos_dos' from data source 
##   `/Users/oscargauss/Documents/studies/master-in-artificial-intelligence-and-data-science-for-business-transformation/m-3-modelamiento-y-visualización-de-la-información/practica-3/bolivia_departamentos_dos.geojson' 
##   using driver `GeoJSON'
## Simple feature collection with 9 features and 1 field
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: -68.6193 ymin: -22 xmax: -62.6561 ymax: -10.5
## Geodetic CRS:  WGS 84
str(departamentos_geo)
## Classes 'sf' and 'data.frame':   9 obs. of  2 variables:
##  $ DEPARTAMEN: chr  "La Paz" "Cochabamba" "Santa Cruz" "Oruro" ...
##  $ geometry  :sfc_POLYGON of length 9; first list element: List of 1
##   ..$ : num [1:5, 1:2] -68.6 -68.6 -67.6 -67.6 -68.6 ...
##   ..- attr(*, "class")= chr [1:3] "XY" "POLYGON" "sfg"
##  - attr(*, "sf_column")= chr "geometry"
##  - attr(*, "agr")= Factor w/ 3 levels "constant","aggregate",..: NA
##   ..- attr(*, "names")= chr "DEPARTAMEN"

Unir datos

datos_completos <- transacciones %>%
  left_join(clientes, by = "id_cliente") %>%
  left_join(servicios, by = "id_servicio") %>%
  left_join(campañas, by = "id_campana")

datos_completos

Verificar la limpieza de datos: campos faltantes, tipos, formatos de fecha.

# Ver campos faltantes
skimr::skim(datos_completos)
Data summary
Name datos_completos
Number of rows 5000
Number of columns 17
_______________________
Column type frequency:
character 8
Date 1
numeric 8
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
nombre 0 1 9 12 0 995 0
genero 0 1 4 9 0 3 0
departamento.x 0 1 4 10 0 9 0
ciudad 0 1 5 11 0 14 0
nombre_servicio 0 1 3 15 0 5 0
categoria 0 1 11 17 0 4 0
nombre_campana 0 1 9 11 0 300 0
departamento.y 0 1 4 10 0 9 0

Variable type: Date

skim_variable n_missing complete_rate min max median n_unique
fecha 0 1 2023-01-01 2023-12-31 2023-07-01 365

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
id_transaccion 0 1 2500.50 1443.52 1.0 1250.75 2500.50 3750.25 5000.00 ▇▇▇▇▇
id_cliente 0 1 500.81 286.10 1.0 257.75 505.00 747.00 1000.00 ▇▇▇▇▇
id_servicio 0 1 102.06 58.16 1.0 52.00 101.00 154.00 200.00 ▇▇▇▇▇
id_campana 0 1 152.17 86.36 1.0 78.00 153.00 228.00 300.00 ▇▇▇▇▇
cantidad 0 1 5.00 2.59 1.0 3.00 5.00 7.00 9.00 ▇▇▃▇▇
total 0 1 5176.77 4024.42 108.8 1849.24 3957.19 7610.85 17946.54 ▇▅▃▂▁
edad 0 1 41.01 13.49 18.0 29.00 41.00 52.00 64.00 ▇▇▇▇▇
precio_unitario 0 1 1039.04 541.45 108.8 535.58 996.93 1508.13 1994.06 ▇▇▇▆▇
# Ver tipos de datos y fechas
glimpse(datos_completos)
## Rows: 5,000
## Columns: 17
## $ id_transaccion  <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,…
## $ id_cliente      <dbl> 450, 892, 276, 888, 30, 534, 814, 711, 831, 777, 680, …
## $ id_servicio     <dbl> 29, 156, 192, 56, 78, 21, 74, 97, 160, 38, 142, 125, 1…
## $ id_campana      <dbl> 295, 125, 221, 210, 295, 158, 25, 15, 108, 166, 254, 2…
## $ cantidad        <dbl> 5, 2, 7, 4, 5, 9, 5, 4, 8, 8, 7, 1, 1, 9, 2, 9, 9, 6, …
## $ total           <dbl> 3908.90, 1922.50, 12621.28, 2769.08, 3784.10, 3290.13,…
## $ fecha           <date> 2023-01-11, 2023-07-14, 2023-04-29, 2023-09-18, 2023-…
## $ nombre          <chr> "Cliente_450", "Cliente_892", "Cliente_276", "Cliente_…
## $ edad            <dbl> 39, 62, 20, 40, 44, 53, 22, 23, 21, 47, 28, 29, 51, 34…
## $ genero          <chr> "Femenino", "Femenino", "Otro", "Femenino", "Masculino…
## $ departamento.x  <chr> "La Paz", "La Paz", "Pando", "Chuquisaca", "Oruro", "T…
## $ ciudad          <chr> "La Paz", "El Alto", "Cobija", "Sucre", "Oruro", "Yacu…
## $ nombre_servicio <chr> "Redes Sociales", "SEO", "Contenido", "SEO", "Redes So…
## $ categoria       <chr> "Creatividad", "Desarrollo Web", "Creatividad", "Desar…
## $ precio_unitario <dbl> 781.78, 961.25, 1803.04, 692.27, 756.82, 365.57, 1318.…
## $ nombre_campana  <chr> "Campaña_295", "Campaña_125", "Campaña_221", "Campaña_…
## $ departamento.y  <chr> "Tarija", "Cochabamba", "Beni", "Tarija", "Tarija", "B…
# Convertir fechas si es necesario
datos_completos <- datos_completos %>%
  mutate(fecha_transaccion = ymd(fecha))
unique(datos_completos$departamento.x)
## [1] "La Paz"     "Pando"      "Chuquisaca" "Oruro"      "Tarija"    
## [6] "Beni"       "Santa Cruz" "Cochabamba" "Potosí"

3.Verificar los departamentos que coincidan con el geojson.

unique(departamentos_geo$DEPARTAMEN)
## [1] "La Paz"     "Cochabamba" "Santa Cruz" "Oruro"      "Potosí"    
## [6] "Chuquisaca" "Tarija"     "Beni"       "Pando"

Parte 2: Visualizaciones interactivas

Crear entre 6 y 8 gráficos interactivos. Algunos ejemplos sugeridos:

Ventas por Categoría de Servicio

# Librerías necesarias
library(tidyverse)
library(plotly)

# Unir y procesar
ventas_por_categoria <- transacciones %>%
  left_join(servicios, by = "id_servicio") %>%
  group_by(categoria) %>%
  summarise(total_ventas = sum(total, na.rm = TRUE)) %>%
  arrange(desc(total_ventas))

# Graficar
plot_ly(
  data = ventas_por_categoria,
  x = ~categoria,
  y = ~total_ventas,
  type = "bar",
  text = ~paste("Bs.", total_ventas),
  marker = list(color = "steelblue")
) %>%
  layout(
    title = "Ventas por Categoría de Servicio",
    xaxis = list(title = "Categoría de Servicio"),
    yaxis = list(title = "Total de Ventas (Bs.)")
  )

Distribución de Clientes por Edad

# Librerías necesarias
library(tidyverse)
library(plotly)

# Crear rangos de edad
clientes <- clientes %>%
  mutate(
    rango_edad = cut(
      edad,
      breaks = c(0, 18, 25, 35, 45, 55, 65, 100),
      labels = c("0-18", "19-25", "26-35", "36-45", "46-55", "56-65", "66+"),
      right = FALSE
    )
  )

# Contar clientes por rango
distribucion_edad <- clientes %>%
  count(rango_edad) %>%
  arrange(rango_edad)

# Gráfico interactivo
plot_ly(
  data = distribucion_edad,
  x = ~rango_edad,
  y = ~n,
  type = "bar",
  marker = list(color = 'darkorange'),
  text = ~n,
  textposition = 'auto'
) %>%
  layout(
    title = "Distribución de Clientes por Edad",
    xaxis = list(title = "Rango de Edad"),
    yaxis = list(title = "Cantidad de Clientes")
  )

Ventas por Departamento

# Librerías necesarias
library(tidyverse)
library(plotly)

# Unir transacciones con clientes para obtener departamento
ventas_por_departamento <- transacciones %>%
  rename(id_cliente = id_cliente) %>%
  left_join(clientes, by = "id_cliente")

# Agrupar por departamento y sumar total de ventas
ventas_departamento <- ventas_por_departamento %>%
  group_by(departamento) %>%
  summarise(total_ventas = sum(total, na.rm = TRUE)) %>%
  arrange(desc(total_ventas))

# Crear gráfico interactivo
plot_ly(
  data = ventas_departamento,
  x = ~departamento,
  y = ~total_ventas,
  type = "bar",
  marker = list(color = "steelblue"),
  text = ~paste("Bs.", total_ventas),
  textposition = "auto"
) %>%
  layout(
    title = "Ventas por Departamento",
    xaxis = list(title = "Departamento"),
    yaxis = list(title = "Total de Ventas (Bs.)")
  )

Ventas por Género

# Librerías necesarias
library(tidyverse)
library(plotly)

# Unir transacciones con clientes para obtener el género
ventas_por_genero <- transacciones %>%
  left_join(clientes, by = "id_cliente")

# Agrupar por género y sumar total de ventas
ventas_genero <- ventas_por_genero %>%
  group_by(genero) %>%
  summarise(total_ventas = sum(total, na.rm = TRUE)) %>%
  arrange(desc(total_ventas))

# Gráfico interactivo
plot_ly(
  data = ventas_genero,
  x = ~genero,
  y = ~total_ventas,
  type = "bar",
  text = ~paste("Bs.", total_ventas),
  marker = list(color = "mediumseagreen"),
  textposition = "auto"
) %>%
  layout(
    title = "Ventas por Género",
    xaxis = list(title = "Género"),
    yaxis = list(title = "Total de Ventas (Bs.)")
  )

Participación por Ciudad

# Librerías necesarias
library(tidyverse)
library(plotly)

# Unir transacciones con clientes para obtener ciudad
participacion_ciudad <- transacciones %>%
  left_join(clientes, by = "id_cliente")

# Contar transacciones por ciudad
conteo_ciudad <- participacion_ciudad %>%
  group_by(ciudad) %>%
  summarise(participacion = n()) %>%
  arrange(desc(participacion))

# Crear gráfico interactivo
plot_ly(
  data = conteo_ciudad,
  x = ~reorder(ciudad, -participacion),
  y = ~participacion,
  type = "bar",
  marker = list(color = "tomato"),
  text = ~paste("Transacciones:", participacion),
  textposition = "auto"
) %>%
  layout(
    title = "Participación por Ciudad (número de transacciones)",
    xaxis = list(title = "Ciudad", tickangle = -45),
    yaxis = list(title = "Cantidad de Transacciones")
  )

Tendencias de Ventas por Fecha

# Librerías necesarias
library(tidyverse)
library(plotly)

transacciones <- transacciones %>%
  mutate(fecha = as.Date(fecha))

# Agrupar por fecha y sumar ventas
ventas_por_fecha <- transacciones %>%
  group_by(fecha) %>%
  summarise(total_ventas = sum(total, na.rm = TRUE)) %>%
  arrange(fecha)

# Crear gráfico de líneas interactivo
plot_ly(
  data = ventas_por_fecha,
  x = ~fecha,
  y = ~total_ventas,
  type = 'scatter',
  mode = 'lines+markers',
  line = list(color = 'royalblue'),
  marker = list(size = 5)
) %>%
  layout(
    title = "Tendencias de Ventas por Fecha",
    xaxis = list(title = "Fecha"),
    yaxis = list(title = "Total de Ventas (Bs.)")
  )

Histograma de frecuencias

# Librerías necesarias
library(tidyverse)
library(plotly)

# Graficar histograma interactivo con plotly
plot_ly(
  data = transacciones,
  x = ~total,
  type = "histogram",
  nbinsx = 30,  # número de barras (bins)
  marker = list(color = "purple")
) %>%
  layout(
    title = "Histograma de Frecuencias de Montos por Transacción",
    xaxis = list(title = "Monto Total de la Transacción (Bs.)"),
    yaxis = list(title = "Frecuencia")
  )

Dispersión entre edad y monto

# Librerías necesarias
library(tidyverse)
library(plotly)

# Unir transacciones con clientes
datos_dispersion <- transacciones %>%
  left_join(clientes, by = "id_cliente")

# Crear gráfico de dispersión
plot_ly(
  data = datos_dispersion,
  x = ~edad,
  y = ~total,
  type = 'scatter',
  mode = 'markers',
  marker = list(size = 7, color = 'rgba(0, 123, 255, 0.6)', line = list(width = 1, color = 'darkblue')),
  text = ~paste("Cliente:", nombre, "<br>Género:", genero)
) %>%
  layout(
    title = "Dispersión entre Edad y Monto de Transacción",
    xaxis = list(title = "Edad del Cliente"),
    yaxis = list(title = "Monto Total de la Transacción (Bs.)")
  )

Parte 3: Visualización geoespacial con rutas

1. Utilizar el archivo GeoJSON para mapear los departamentos de Bolivia.

library(sf)
library(leaflet)
library(dplyr)
library(RColorBrewer)

# Leer el GeoJSON
departamentos_geo <- st_read("bolivia_departamentos_dos.geojson")
## Reading layer `bolivia_departamentos_dos' from data source 
##   `/Users/oscargauss/Documents/studies/master-in-artificial-intelligence-and-data-science-for-business-transformation/m-3-modelamiento-y-visualización-de-la-información/practica-3/bolivia_departamentos_dos.geojson' 
##   using driver `GeoJSON'
## Simple feature collection with 9 features and 1 field
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: -68.6193 ymin: -22 xmax: -62.6561 ymax: -10.5
## Geodetic CRS:  WGS 84
# Asegurar sistema de coordenadas compatible con Leaflet
departamentos_geo <- st_transform(departamentos_geo, crs = 4326)

2. Dibujar 4 rutas comerciales/turísticas entre diferentes departamentos que incluyan 2 o más ciudades intermedias por ruta.

rutas <- list(
  Ruta1 = data.frame(
    ciudad = c("La Paz", "Oruro", "Potosí", "Tarija"),
    lat = c(-16.5, -17.98, -19.58, -21.53),
    lng = c(-68.15, -67.12, -65.75, -64.73)
  ),
  Ruta2 = data.frame(
    ciudad = c("Santa Cruz", "Cochabamba", "Sucre"),
    lat = c(-17.78, -17.39, -19.04),
    lng = c(-63.18, -66.15, -65.26)
  ),
  Ruta3 = data.frame(
    ciudad = c("Cobija", "Riberalta", "Trinidad"),
    lat = c(-11.02, -11.01, -14.83),
    lng = c(-68.77, -66.13, -64.90)
  ),
  Ruta4 = data.frame(
    ciudad = c("Villazón", "Uyuni", "La Paz"),
    lat = c(-22.08, -20.46, -16.5),
    lng = c(-65.6, -66.83, -68.15)
  )
)

3. Mostrar un mapa donde se pueda:

  • Visualizar cada ruta con distinto color.

  • Ver información al pasar el mouse (tooltip).

  • Aplicar un filtro que permita seleccionar qué ruta mostrar.

# Paleta de colores para las rutas
colores <- brewer.pal(4, "Set1")

# Mapa base con departamentos
mapa <- leaflet() %>%
  addTiles() %>%
  addPolygons(
    data = departamentos_geo,
    fillColor = "transparent",
    color = "gray",
    weight = 1,
    label = ~DEPARTAMEN
  )

# Agregar rutas y marcadores
for (i in seq_along(rutas)) {
  nombre_ruta <- names(rutas)[i]
  puntos <- rutas[[i]]
  coords <- as.matrix(puntos[, c("lng", "lat")])

  # Añadir línea de ruta
  mapa <- mapa %>%
    addPolylines(
      lng = coords[,1],
      lat = coords[,2],
      color = colores[i],
      weight = 4,
      opacity = 0.8,
      group = nombre_ruta,
      popup = paste("<b>", nombre_ruta, "</b><br>Ruta: ", paste(puntos$ciudad, collapse = " → "))
    ) %>%
    addCircleMarkers(
      lng = puntos$lng,
      lat = puntos$lat,
      label = puntos$ciudad,
      radius = 6,
      color = colores[i],
      fillOpacity = 0.9,
      group = nombre_ruta
    )
}

# Añadir control de capas (filtro por ruta)
mapa <- mapa %>%
  addLayersControl(
    overlayGroups = names(rutas),
    options = layersControlOptions(collapsed = FALSE)
  )

# Mostrar el mapa
mapa

Parte 4: KPIs

Mostrar al menos 3 indicadores clave en el dashboard.

# Librerías necesarias
library(shiny)
library(bs4Dash)
## 
## Attaching package: 'bs4Dash'
## The following objects are masked from 'package:shiny':
## 
##     actionButton, column, insertTab, navbarMenu, tabsetPanel
## The following object is masked from 'package:graphics':
## 
##     box
library(tidyverse)
library(scales)
## 
## Attaching package: 'scales'
## The following object is masked from 'package:purrr':
## 
##     discard
## The following object is masked from 'package:readr':
## 
##     col_factor
total_ingresos <- sum(transacciones$total, na.rm = TRUE)
total_clientes <- n_distinct(transacciones$id_cliente)
total_transacciones <- nrow(transacciones)
servicio_mas_solicitado <- transacciones %>%
  count(id_servicio, sort = TRUE) %>%
  left_join(servicios, by = "id_servicio") %>%
  slice(1) %>%
  select(nombre_servicio, n)
ventas_por_departamento <- transacciones %>%
  left_join(clientes, by = "id_cliente") %>%
  group_by(departamento) %>%
  summarise(total_ventas = sum(total, na.rm = TRUE)) %>%
  arrange(desc(total_ventas)) %>%
  slice(1)

Parte 5: Créditos

Resultado:

ui <- bs4DashPage(
  title = "Dashboard de KPIs",
  header = bs4DashNavbar(title = "Indicadores Clave de Marketing"),
  sidebar = bs4DashSidebar(
    skin = "light",
    status = "primary",
    bs4SidebarMenu(
      bs4SidebarMenuItem("KPIs", tabName = "kpis", icon = icon("chart-line")),
      bs4SidebarMenuItem("Créditos", tabName = "creditos", icon = icon("info-circle"))
    )
  ),
  body = bs4DashBody(
    bs4TabItems(
      # TAB KPIs
      bs4TabItem(tabName = "kpis",
                 h2("KPIs del Sistema de Marketing"),
                 fluidRow(
                   bs4ValueBox(value = dollar_format(prefix = "Bs. ")(total_ingresos),
                               subtitle = "Total de Ingresos",
                               color = "success", icon = icon("dollar-sign"), width = 6),
                   bs4ValueBox(value = total_clientes,
                               subtitle = "Clientes Únicos",
                               color = "info", icon = icon("users"), width = 6)
                 ),
                 fluidRow(
                   bs4ValueBox(value = total_transacciones,
                               subtitle = "Total de Transacciones",
                               color = "warning", icon = icon("receipt"), width = 6),
                   bs4ValueBox(value = servicio_mas_solicitado,
                               subtitle = "Servicio Más Solicitado",
                               color = "indigo", icon = icon("star"), width = 6)
                 ),
                 fluidRow(
                   bs4ValueBox(value = ventas_por_departamento,
                               subtitle = "Departamento con Más Ventas",
                               color = "danger", icon = icon("map-marker-alt"), width = 12)
                 )
      ),
      
      # TAB CRÉDITOS
      bs4TabItem(tabName = "creditos",
                 h3("Créditos del Proyecto"),
                 bs4Card(width = 12, solidHeader = TRUE,
                         HTML("
            <div style='font-size: 18px; line-height: 1.6; padding: 20px;'>
              <strong>Nombre del Estudiante:</strong> Oscar Gauss Carvajal Yucra<br>
              <strong>Carrera:</strong> Informática<br>
              <strong>Módulo:</strong> Visualización de Datos<br>
              <strong>Universidad:</strong> Universidad Mayor de San Andres<br>
              <strong>Docente:</strong> Diego Parraga Menchaca<br>
              <strong>Gestión:</strong> 2025 - Primer Semestre
            </div>
          ")
                 )
      )
    )
  )
)

server <- function(input, output) {}

shinyApp(ui, server)
Shiny applications not supported in static R Markdown documents