Benchmarking Financiero: Análisis de Rentabilidad

Author

Departamento de Análisis de Datos

Published

January 26, 2026

Introducción

La formulación definida para cada indicador, están descritas en el Título V de la Circular Básica Contable y Finaciiera de la Supersolidaria

1. Saldo de la cartera.

En este gráfico comparamos el comportamiento de la Cartera Bruta, entre la Cooperativa UNIMOS vs las 173 Cooperativas de Ahorro y Crédito

Code
# Preparación de datos:

#| label: grafico-cartera-minimalista
#| warning: false
#| message: false

library(dplyr)
library(readr)
library(ggplot2)

# 1. Carga de datos
Saldo_Cartera_Bruta_Unimos <- read_csv("data/Saldo Cartera Bruta_Unimos.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))

Saldo_Cartera_Bruta_Sector <- read_csv("data/Saldo Cartera Bruta_Sector.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))

# 2. Preparación y Unión
sector_preparado <- Saldo_Cartera_Bruta_Sector %>%
  mutate(Tipo = "Sector") %>%
  rename(Valor = `1.1.7 Cartera Total`)

unimos_preparado <- Saldo_Cartera_Bruta_Unimos %>%
  mutate(Tipo = "Unimos") %>%
  rename(Valor = `1.1.7 Cartera Total`)

Cartera_Consolidada <- bind_rows(sector_preparado, unimos_preparado) %>%
  mutate(Año = as.numeric(Año))

# --- EL PASO QUE FALTABA: Definir factor y crear cartera_plot ---
f_cartera <- 200  # Factor para equilibrar Billones vs Miles de Millones

cartera_plot <- Cartera_Consolidada %>%
  mutate(
    # Escalamos visualmente Unimos
    Valor_Vis = ifelse(Tipo == "Unimos", Valor * f_cartera, Valor),
    # Creamos etiquetas de texto (T para Billones, B para Mil Millones)
    Etiqueta = ifelse(Tipo == "Sector", 
                      paste0(round(Valor / 1e12, 1), "T"), 
                      paste0(round(Valor / 1e9, 1), "B")),
    X_Num = ifelse(Tipo == "Sector", 1, 2)
  )

# 3. Recalcular resumen para el tooltip minimalista
resumen_minimalista <- Cartera_Consolidada %>%
  group_by(Tipo) %>%
  summarize(
    增长_pct = (Valor[Año == 2025] - Valor[Año == 2023]) / Valor[Año == 2023] * 100,
    y_max = max(Valor)
  ) %>%
  mutate(
    X_Num = ifelse(Tipo == "Sector", 1, 2),
    y_vis_max = ifelse(Tipo == "Unimos", y_max * f_cartera, y_max),
    Label_Text = paste0("Δ ", round(增长_pct, 1), "%")
  )

# 4. Gráfico Final
ggplot(cartera_plot, aes(x = X_Num, y = Valor_Vis, fill = factor(Año))) +
  annotate("rect", xmin = 1.5, xmax = 2.5, ymin = 0, ymax = Inf, fill = "#F0F7FB", alpha = 0.3) +
  geom_col(position = position_dodge(width = 0.8), width = 0.7, color = "white", linewidth = 0.1) +
  
  # Tooltip Δ %
  geom_text(data = resumen_minimalista, 
            aes(x = X_Num, y = y_vis_max * 1.15, label = Label_Text),
            inherit.aes = FALSE, size = 3.5, fontface = "bold", color = "#566573") +
  geom_segment(data = resumen_minimalista,
               aes(x = X_Num - 0.2, xend = X_Num + 0.2, y = y_vis_max * 1.08, yend = y_vis_max * 1.08),
               inherit.aes = FALSE, color = "#AEB6BF", linewidth = 0.3) +

  # Etiquetas de valores
  geom_text(aes(label = Etiqueta), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 2.8, color = "grey30") +
  
  scale_x_continuous(breaks = c(1, 2), labels = c("SECTOR", "UNIMOS")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.25)), labels = NULL, name = NULL) +
  scale_fill_manual(values = c("2023" = "#D5DBDB", "2024" = "#5D6D7E", "2025" = "#E67E22"), name = NULL) +
  
  labs(title = "Crecimiento Acumulado de Cartera", 
       subtitle = "Variación porcentual periodo 2023-2025") +
  theme_void() +
  theme(
    plot.margin = margin(20, 20, 20, 20),
    plot.title = element_text(face = "bold", size = 12, hjust = 0.5, color = "#2C3E50"),
    plot.subtitle = element_text(size = 9, hjust = 0.5, color = "#7F8C8D", margin = margin(b = 20)),
    axis.text.x = element_text(size = 9, face = "bold", color = "#2C3E50", margin = margin(t = 10)),
    legend.position = "bottom"
  )

Relación de eficiencia: Ingresos vs Costos por Unidad.

Conclusiones

  • El Sector cerró con 19.5 Billones, mientras que Unimos alcanzó los 89 Mil Millones.

Unimos está creciendo al doble de velocidad que el mercado.

  • El sector presenta un aumento consolidado del 12.7% en el periodo 2023-2025.

  • Unimos registra un desempeño superior con un 25% de crecimiento acumulado en el mismo periodo.

2. Saldo de cartera en riesgo

Con respecto al saldo de la cartera bruta, tenemos la cartera en riesgo que es toda aquella cartera que no está calificada en A.

Code
library(dplyr)
library(readr)
library(ggplot2)

# 1. Carga de datos de Riesgo
Saldo_Riesgo_Unimos <- read_csv("data/Saldo Cartera Riesgo_Unimos.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))

Saldo_Riesgo_Sector <- read_csv("data/Saldo Cartera Riesgo_Sector.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))

# 2. Preparación y Unión (Columna 1.3.7 para Riesgo)
sector_riesgo_preparado <- Saldo_Riesgo_Sector %>%
  mutate(Tipo = "Sector") %>%
  rename(Valor = `1.3.7 Cartera Total`)

unimos_riesgo_preparado <- Saldo_Riesgo_Unimos %>%
  mutate(Tipo = "Unimos") %>%
  rename(Valor = `1.3.7 Cartera Total`)

Riesgo_Consolidado <- bind_rows(sector_riesgo_preparado, unimos_riesgo_preparado) %>%
  mutate(Año = as.numeric(Año))

# 3. Definición de Escalas y Plot Data con nomenclatura Colombiana
f_escala <- 200  

riesgo_plot <- Riesgo_Consolidado %>%
  mutate(
    Valor_Vis = ifelse(Tipo == "Unimos", Valor * f_escala, Valor),
    # AJUSTE COLOMBIANO: "Bill" para billones y "M mill" para miles de millones
    Etiqueta = ifelse(Tipo == "Sector", 
                      paste0(round(Valor / 1e12, 1), " Bill"), 
                      paste0(round(Valor / 1e9, 1), " M mill")),
    X_Num = ifelse(Tipo == "Sector", 1, 2)
  )

# 4. Resumen para Tooltip (Variación Acumulada)
resumen_riesgo <- Riesgo_Consolidado %>%
  group_by(Tipo) %>%
  summarize(
    增长_pct = (Valor[Año == 2025] - Valor[Año == 2023]) / Valor[Año == 2023] * 100,
    y_max = max(Valor)
  ) %>%
  mutate(
    X_Num = ifelse(Tipo == "Sector", 1, 2),
    y_vis_max = ifelse(Tipo == "Unimos", y_max * f_escala, y_max),
    Label_Text = paste0("Δ ", round(增长_pct, 1), "%")
  )

# 5. Gráfico Final con Estilo Minimalista
ggplot(riesgo_plot, aes(x = X_Num, y = Valor_Vis, fill = factor(Año))) +
  annotate("rect", xmin = 1.5, xmax = 2.5, ymin = 0, ymax = Inf, fill = "#F0F7FB", alpha = 0.3) +
  geom_col(position = position_dodge(width = 0.8), width = 0.7, color = "white", linewidth = 0.1) +
  
  # Tooltip Δ %
  geom_text(data = resumen_riesgo, 
            aes(x = X_Num, y = y_vis_max * 1.15, label = Label_Text),
            inherit.aes = FALSE, size = 3.5, fontface = "bold", color = "#566573") +
  geom_segment(data = resumen_riesgo,
               aes(x = X_Num - 0.2, xend = X_Num + 0.2, y = y_vis_max * 1.08, yend = y_vis_max * 1.08),
               inherit.aes = FALSE, color = "#AEB6BF", linewidth = 0.3) +

  # Etiquetas con nomenclatura "Bill" y "M mill"
  geom_text(aes(label = Etiqueta), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 2.8, color = "grey30") +
  
  scale_x_continuous(breaks = c(1, 2), labels = c("SECTOR", "UNIMOS")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.25)), labels = NULL, name = NULL) +
  scale_fill_manual(values = c("2023" = "#D5DBDB", "2024" = "#5D6D7E", "2025" = "#E67E22"), name = NULL) +
  
  labs(title = "Crecimiento de Cartera en Riesgo (1.3.7)", 
       subtitle = "Variación acumulada periodo 2023-2025 (Cifras en Bill y M mill)") +
  theme_void() +
  theme(
    plot.margin = margin(20, 20, 20, 20),
    plot.title = element_text(face = "bold", size = 12, hjust = 0.5, color = "#2C3E50"),
    plot.subtitle = element_text(size = 9, hjust = 0.5, color = "#7F8C8D", margin = margin(b = 20)),
    axis.text.x = element_text(size = 9, face = "bold", color = "#2C3E50", margin = margin(t = 10)),
    legend.position = "bottom"
  )

#Conclusiones:

  • A pesar del fuerte crecimiento en la colocación, la cartera en riesgo de Unimos se mantuvo controlada con un incremento de apenas el 3% en el trienio.

  • Unimos muestra una gestión de riesgo más prudente que el mercado general; el Sector experimentó un aumento del 4.5% en su saldo en riesgo, superando en 1.5 puntos porcentuales al desempeño de la Cooperativa Unimos.

  • El hecho de que la cartera bruta crezca al 25% mientras el riesgo solo aumenta un 3% es un indicador de crecimiento saludable. Esto sugiere que la expansión de Unimos no se está logrando a costa de relajar los estándares de crédito, sino mediante una gestión comercial eficiente y segura.

3. ICC por riesgo

Y con relación al saldo de cartera bruta vs el saldo en riesgo, obtenemos el ICC por riesgo.

Code
library(dplyr)
library(readr)
library(ggplot2)
library(stringr)

# 1. Carga y Limpieza (Manejando comas decimales)
ICC_Unimos <- read_csv("data/ICC_Unimos.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))

ICC_Sector <- read_csv("data/ICC_Sector.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))

limpiar_icc <- function(df, etiqueta) {
  df %>%
    mutate(
      Tipo = etiqueta,
      # Convertimos "0,0778" -> 7.78
      Valor = as.numeric(str_replace(`1.5.7 Cartera Total`, ",", ".")) * 100
    )
}

ICC_Consolidado <- bind_rows(
  limpiar_icc(ICC_Sector, "Sector"),
  limpiar_icc(ICC_Unimos, "Unimos")
) %>% mutate(Año = as.numeric(Año), X_Num = ifelse(Tipo == "Sector", 1, 2))

# 2. Resumen para Tooltip (Diferencia en puntos porcentuales)
resumen_icc <- ICC_Consolidado %>%
  group_by(Tipo) %>%
  summarize(
    diff_pp = Valor[Año == 2025] - Valor[Año == 2023],
    y_max = max(Valor),
    X_Num = first(X_Num)
  ) %>%
  mutate(
    Label_Delta = paste0("Δ ", round(diff_pp, 2), " p.p.")
  )

# 3. Gráfico Final (Escala Real %)
ggplot(ICC_Consolidado, aes(x = X_Num, y = Valor, fill = factor(Año))) +
  # Sombra de fondo para Unimos
  annotate("rect", xmin = 1.5, xmax = 2.5, ymin = 0, ymax = Inf, fill = "#F0F7FB", alpha = 0.4) +
  
  # Barras
  geom_col(position = position_dodge(width = 0.8), width = 0.7, color = "white", linewidth = 0.2) +
  
  # Tooltip Minimalista (Corregido para escala %)
  geom_text(data = resumen_icc, 
            aes(x = X_Num, y = y_max + 1.2, label = Label_Delta),
            inherit.aes = FALSE, size = 3.8, fontface = "bold", color = "#566573") +
  
  geom_segment(data = resumen_icc,
               aes(x = X_Num - 0.2, xend = X_Num + 0.2, y = y_max + 0.6, yend = y_max + 0.6),
               inherit.aes = FALSE, color = "#AEB6BF", linewidth = 0.5) +

  # Datos sobre las barras
  geom_text(aes(label = paste0(round(Valor, 1), "%")), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 3.2, fontface = "bold", color = "#2C3E50") +
  
  # Configuración de Ejes y Estética
  scale_x_continuous(breaks = c(1, 2), labels = c("SECTOR", "UNIMOS")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.3))) + # Espacio para el delta
  scale_fill_manual(values = c("2023" = "#D5DBDB", "2024" = "#5D6D7E", "2025" = "#E67E22"), name = NULL) +
  
  labs(title = "Índice de Calidad de Cartera (1.5.7)", 
       subtitle = "Variación en puntos porcentuales (p.p.) entre 2023 y 2025") +
  theme_void() +
  theme(
    plot.margin = margin(20, 20, 20, 20),
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5, color = "#2C3E50"),
    plot.subtitle = element_text(size = 10, hjust = 0.5, color = "#7F8C8D", margin = margin(b = 25)),
    axis.text.x = element_text(size = 10, face = "bold", color = "#2C3E50", margin = margin(t = 10)),
    legend.position = "bottom"
  )

Conclusiones

  • El Sector muestra una tendencia incremental en su indicador de riesgo, pasando de 7.8% en 2023 a 8.2% en 2025. Esto representa un deterioro en la calidad de los activos del mercado general de +0.44 p.p. (puntos porcentuales).

  • Al Contrario a la tendencia del mercado, la Cooperativa ha logrado reducir su índice de calidad de manera constante, pasando de un 8.6% en 2023 a un sólido 7.1% al cierre de 2025.

  • Unimos registra una mejora de -1.51 p.p. en su ICC durante el trienio analizado. Esta cifra es relevante porque ocurre en el mismo periodo donde la cartera bruta creció un 25%, demostrando que el crecimiento no comprometió la calidad de la cartera.

#4. Saldo de Depósitos

Code
#| label: grafico-depositos-minimalista
#| warning: false
#| message: false

library(dplyr)
library(readr)
library(ggplot2)

Saldo_Depositos_Sector <- read_csv("data/Saldo Depositos_Sector.csv", 
    col_types = cols(Año = col_character(), 
        `Nombre Mes Corto` = col_skip()))

Saldo_Depositos_Unimos <- read_csv("data/Saldo Depositos_Unimos.csv", 
    col_types = cols(Año = col_character(), 
        `Nombre Mes Corto` = col_skip()))

# 1. Preparación y Unión
# La columna es `5.2.2 Saldo en depositos`
sector_dep_preparado <- Saldo_Depositos_Sector %>%
  mutate(Tipo = "Sector") %>%
  rename(Valor = `5.2.2 Saldo en depositos`)

unimos_dep_preparado <- Saldo_Depositos_Unimos %>%
  mutate(Tipo = "Unimos") %>%
  rename(Valor = `5.2.2 Saldo en depositos`)

Depositos_Consolidado <- bind_rows(sector_dep_preparado, unimos_dep_preparado) %>%
  mutate(Año = as.numeric(Año))

# 2. Definición de Escalas y Plot Data con nomenclatura Colombiana
f_escala_dep <- 200  

depositos_plot <- Depositos_Consolidado %>%
  mutate(
    Valor_Vis = ifelse(Tipo == "Unimos", Valor * f_escala_dep, Valor),
    # Nomenclatura Colombiana: Bill y M mill
    Etiqueta = ifelse(Tipo == "Sector", 
                      paste0(round(Valor / 1e12, 1), " Bill"), 
                      paste0(round(Valor / 1e9, 1), " M mill")),
    X_Num = ifelse(Tipo == "Sector", 1, 2)
  )

# 3. Resumen para Tooltip (Crecimiento Acumulado 2023-2025)
resumen_dep <- Depositos_Consolidado %>%
  group_by(Tipo) %>%
  summarize(
    crecimiento_pct = (Valor[Año == 2025] - Valor[Año == 2023]) / Valor[Año == 2023] * 100,
    y_max = max(Valor)
  ) %>%
  mutate(
    X_Num = ifelse(Tipo == "Sector", 1, 2),
    y_vis_max = ifelse(Tipo == "Unimos", y_max * f_escala_dep, y_max),
    Label_Text = paste0("Δ ", round(crecimiento_pct, 1), "%")
  )

# 4. Gráfico Final Minimalista
ggplot(depositos_plot, aes(x = X_Num, y = Valor_Vis, fill = factor(Año))) +
  # Sombra sutil para destacar la entidad
  annotate("rect", xmin = 1.5, xmax = 2.5, ymin = 0, ymax = Inf, fill = "#F0F7FB", alpha = 0.3) +
  
  # Barras
  geom_col(position = position_dodge(width = 0.8), width = 0.7, color = "white", linewidth = 0.1) +
  
  # Tooltip de Variación Acumulada
  geom_text(data = resumen_dep, 
            aes(x = X_Num, y = y_vis_max * 1.15, label = Label_Text),
            inherit.aes = FALSE, size = 3.5, fontface = "bold", color = "#566573") +
  geom_segment(data = resumen_dep,
               aes(x = X_Num - 0.2, xend = X_Num + 0.2, y = y_vis_max * 1.08, yend = y_vis_max * 1.08),
               inherit.aes = FALSE, color = "#AEB6BF", linewidth = 0.3) +

  # Etiquetas de valores (Bill y M mill)
  geom_text(aes(label = Etiqueta), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 2.8, color = "grey30") +
  
  # Estética y Escalas
  scale_x_continuous(breaks = c(1, 2), labels = c("SECTOR", "UNIMOS")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.25)), labels = NULL, name = NULL) +
  scale_fill_manual(values = c("2023" = "#D5DBDB", "2024" = "#5D6D7E", "2025" = "#E67E22"), name = NULL) +
  
  labs(title = "Evolución de Saldo en Depósitos", 
       subtitle = "Comparativa de captación 2023-2025 (Escalas ajustadas 200:1)") +
  theme_void() +
  theme(
    plot.margin = margin(20, 20, 20, 20),
    plot.title = element_text(face = "bold", size = 12, hjust = 0.5, color = "#2C3E50"),
    plot.subtitle = element_text(size = 9, hjust = 0.5, color = "#7F8C8D", margin = margin(b = 20)),
    axis.text.x = element_text(size = 9, face = "bold", color = "#2C3E50", margin = margin(t = 10)),
    legend.position = "bottom"
  )

Conclusiones

Unimos ha logrado un incremento constante en sus depósitos, pasando de 54.1 M mill en 2023 a 64.7 M mill en 2025. Esto representa una variación porcentual acumulada del 19.6%.

El mercado general mostró una expansión más acelerada del 24.5%, cerrando el periodo con un saldo de 14.7 Bill.

  • Al contrastar este gráfico con el de Cartera Bruta (donde Unimos creció al 25%), se observa que la colocación de créditos está creciendo a un ritmo superior a la captación de depósitos (19.6%).

  • Esta brecha positiva hacia la colocación indica una alta rotación y demanda de recursos; sin embargo, sugiere la oportunidad de fortalecer campañas de ahorro y CDATs para mantener niveles óptimos de liquidez y autonomía financiera sin depender de fuentes externas.

#5. Ingresos

Los ingresos totales registrados en la cuenta 400000, nos ayuda a conocer el estado de perdidas y ganancias en terminos generales e individuales

Code
library(dplyr)
library(readr)
library(ggplot2)


Ingresos_Sector <- read_csv("data/Ingresos_Sector.csv", 
    col_types = cols(Año = col_character(), 
        `Nombre Mes Corto` = col_skip()))

Ingresos_Unimos <- read_csv("data/Ingresos_Unimos.csv", 
    col_types = cols(Año = col_character(), 
        `Nombre Mes Corto` = col_skip()))



# 1. Preparación y Unión de Datos de Ingresos
sector_ing_preparado <- Ingresos_Sector %>%
  mutate(Tipo = "Sector") %>%
  rename(Valor = Ingresos)

unimos_ing_preparado <- Ingresos_Unimos %>%
  mutate(Tipo = "Unimos") %>%
  rename(Valor = Ingresos)

Ingresos_Consolidado <- bind_rows(sector_ing_preparado, unimos_ing_preparado) %>%
  mutate(Año = as.numeric(Año))

# 2. Configuración de Escala y Nomenclatura Colombiana
f_escala_ing <- 200  

ingresos_plot <- Ingresos_Consolidado %>%
  mutate(
    Valor_Vis = ifelse(Tipo == "Unimos", Valor * f_escala_ing, Valor),
    # Etiquetas: Bill para Billones, M mill para Miles de Millones
    Etiqueta = ifelse(Tipo == "Sector", 
                      paste0(round(Valor / 1e12, 1), " Bill"), 
                      paste0(round(Valor / 1e9, 1), " M mill")),
    X_Num = ifelse(Tipo == "Sector", 1, 2)
  )

# 3. Cálculo de Variación Acumulada (2023-2025)
resumen_ing <- Ingresos_Consolidado %>%
  group_by(Tipo) %>%
  summarize(
    crecimiento_pct = (Valor[Año == 2025] - Valor[Año == 2023]) / Valor[Año == 2023] * 100,
    y_max = max(Valor)
  ) %>%
  mutate(
    X_Num = ifelse(Tipo == "Sector", 1, 2),
    y_vis_max = ifelse(Tipo == "Unimos", y_max * f_escala_ing, y_max),
    Label_Text = paste0("Δ ", round(crecimiento_pct, 1), "%")
  )

# 4. Generación del Gráfico Minimalista
ggplot(ingresos_plot, aes(x = X_Num, y = Valor_Vis, fill = factor(Año))) +
  # Fondo destacado para Unimos
  annotate("rect", xmin = 1.5, xmax = 2.5, ymin = 0, ymax = Inf, fill = "#F0F7FB", alpha = 0.3) +
  
  # Barras con colores institucionales
  geom_col(position = position_dodge(width = 0.8), width = 0.7, color = "white", linewidth = 0.1) +
  
  # Indicador de Variación Acumulada (Tooltip)
  geom_text(data = resumen_ing, 
            aes(x = X_Num, y = y_vis_max * 1.15, label = Label_Text),
            inherit.aes = FALSE, size = 3.5, fontface = "bold", color = "#566573") +
  
  geom_segment(data = resumen_ing,
               aes(x = X_Num - 0.2, xend = X_Num + 0.2, y = y_vis_max * 1.08, yend = y_vis_max * 1.08),
               inherit.aes = FALSE, color = "#AEB6BF", linewidth = 0.3) +

  # Etiquetas de valores financieros
  geom_text(aes(label = Etiqueta), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 2.8, color = "grey30") +
  
  # Estética General
  scale_x_continuous(breaks = c(1, 2), labels = c("SECTOR", "UNIMOS")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.25)), labels = NULL, name = NULL) +
  scale_fill_manual(values = c("2023" = "#D5DBDB", "2024" = "#5D6D7E", "2025" = "#E67E22"), name = NULL) +
  
  labs(title = "Evolución de Ingresos Totales", 
       subtitle = "Comparativa de generación de ingresos 2023-2025 (Cifras en Bill y M mill)") +
  theme_void() +
  theme(
    plot.margin = margin(20, 20, 20, 20),
    plot.title = element_text(face = "bold", size = 12, hjust = 0.5, color = "#2C3E50"),
    plot.subtitle = element_text(size = 9, hjust = 0.5, color = "#7F8C8D", margin = margin(b = 20)),
    axis.text.x = element_text(size = 9, face = "bold", color = "#2C3E50", margin = margin(t = 10)),
    legend.position = "bottom"
  )

Análisis

  • El sector presenta un crecimiento constante y sólido, acumulando un 15.1% de incremento en el trienio. Finaliza 2025 con un volumen total de 3.4 Billones (Bill) de pesos.

  • La cooperativa logra un crecimiento acumulado del 10%. aunque en 2025 se observa una leve estabilización en 12.5 M mill.

6. Gastos

Los gastos totales registrados en la cuenta 500000, nos ayuda a conocer el estado de perdidas y ganancias en terminos generales e individuales

Code
library(dplyr)
library(readr)
library(ggplot2)

# 1. Carga de datos desde archivos CSV
# Es importante que los archivos estén en la carpeta 'data/' de tu proyecto
Gastos_Unimos <- read_csv("data/Gastos_Unimos.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))

Gastos_Sector <- read_csv("data/Gastos_Sector.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))

# 2. Preparación y Unión
sector_gas_preparado <- Gastos_Sector %>%
  mutate(Tipo = "Sector") %>%
  rename(Valor = Gastos)

unimos_gas_preparado <- Gastos_Unimos %>%
  mutate(Tipo = "Unimos") %>%
  rename(Valor = Gastos)

Gastos_Consolidado <- bind_rows(sector_gas_preparado, unimos_gas_preparado) %>%
  mutate(Año = as.numeric(Año))

# 3. Configuración de Escala y Nomenclatura Colombiana
f_escala_gas <- 200  

gastos_plot <- Gastos_Consolidado %>%
  mutate(
    Valor_Vis = ifelse(Tipo == "Unimos", Valor * f_escala_gas, Valor),
    # Etiquetas profesionales: Bill para Billones, M mill para Miles de Millones
    Etiqueta = ifelse(Tipo == "Sector", 
                      paste0(round(Valor / 1e12, 1), " Bill"), 
                      paste0(round(Valor / 1e9, 1), " M mill")),
    X_Num = ifelse(Tipo == "Sector", 1, 2)
  )

# 4. Cálculo de Variación Acumulada para el Tooltip (2023-2025)
resumen_gas <- Gastos_Consolidado %>%
  group_by(Tipo) %>%
  summarize(
    crecimiento_pct = (Valor[Año == 2025] - Valor[Año == 2023]) / Valor[Año == 2023] * 100,
    y_max = max(Valor)
  ) %>%
  mutate(
    X_Num = ifelse(Tipo == "Sector", 1, 2),
    y_vis_max = ifelse(Tipo == "Unimos", y_max * f_escala_gas, y_max),
    Label_Text = paste0("Δ ", round(crecimiento_pct, 1), "%")
  )

# 5. Generación del Gráfico Final
ggplot(gastos_plot, aes(x = X_Num, y = Valor_Vis, fill = factor(Año))) +
  # Sombra de fondo para resaltar a Unimos
  annotate("rect", xmin = 1.5, xmax = 2.5, ymin = 0, ymax = Inf, fill = "#F0F7FB", alpha = 0.3) +
  
  # Barras
  geom_col(position = position_dodge(width = 0.8), width = 0.7, color = "white", linewidth = 0.1) +
  
  # Tooltip de Variación Acumulada (%)
  geom_text(data = resumen_gas, 
            aes(x = X_Num, y = y_vis_max * 1.15, label = Label_Text),
            inherit.aes = FALSE, size = 3.5, fontface = "bold", color = "#566573") +
  geom_segment(data = resumen_gas,
               aes(x = X_Num - 0.2, xend = X_Num + 0.2, y = y_vis_max * 1.08, yend = y_vis_max * 1.08),
               inherit.aes = FALSE, color = "#AEB6BF", linewidth = 0.3) +

  # Etiquetas de valores financieros (Bill y M mill)
  geom_text(aes(label = Etiqueta), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 2.8, color = "grey30") +
  
  # Ejes y Estética
  scale_x_continuous(breaks = c(1, 2), labels = c("SECTOR", "UNIMOS")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.25)), labels = NULL, name = NULL) +
  scale_fill_manual(values = c("2023" = "#D5DBDB", "2024" = "#5D6D7E", "2025" = "#E67E22"), name = NULL) +
  
  labs(title = "Evolución de Gastos Totales", 
       subtitle = "Comparativa de egresos 2023-2025 (Cifras en Bill y M mill)") +
  theme_void() +
  theme(
    plot.margin = margin(20, 20, 20, 20),
    plot.title = element_text(face = "bold", size = 12, hjust = 0.5, color = "#2C3E50"),
    plot.subtitle = element_text(size = 9, hjust = 0.5, color = "#7F8C8D", margin = margin(b = 20)),
    axis.text.x = element_text(size = 9, face = "bold", color = "#2C3E50", margin = margin(t = 10)),
    legend.position = "bottom"
  )

Análisis: Evolución de Gastos Totales (2023-2025)

  • Eficiencia Operativa: Unimos registra un crecimiento acumulado de gastos del 18.5% en el trienio. Tras un incremento en 2024 (8.9 M mill), la entidad logró una ligera reducción para el cierre de 2025, situándose en 8.8 M mill.

  • Este control de gastos es fundamental, ya que se mantiene significativamente por debajo del crecimiento de la cartera bruta (25%), lo que indica que la expansión de la cooperativa no ha disparado desproporcionadamente sus costos operativos.

  • El Sector muestra una curva de gastos mucho más pronunciada, con un crecimiento acumulado del 25.8%.

7. Costos de Ventas

Los ingresos totales registrados en la cuenta 600000, nos ayuda a conocer el estado de perdidas y ganancias en terminos generales e individuales

Code
library(dplyr)
library(readr)
library(ggplot2)

# 1. Carga de datos
Costo_Ventas_Unimos <- read_csv("data/Costo Ventas_Unimos.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))
Costo_Ventas_Sector <- read_csv("data/Costo Ventas_Sector.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))

# 2. Preparación de datos consolidado
Costo_Consolidado <- bind_rows(
  Costo_Ventas_Sector %>% mutate(Tipo = "Sector") %>% rename(Valor = `Costo de ventas`),
  Costo_Ventas_Unimos %>% mutate(Tipo = "Unimos") %>% rename(Valor = `Costo de ventas`)
) %>% mutate(Año = as.numeric(Año))

# 3. Configuración de Escala Visual y Etiquetas (Sin redondeo forzado)
f_escala_costo <- 200  

costo_plot <- Costo_Consolidado %>%
  mutate(
    Valor_Vis = ifelse(Tipo == "Unimos", Valor * f_escala_costo, Valor),
    # LADO IZQUIERDO (Sector): 2 decimales estrictos en Billones
    # LADO DERECHO (Unimos): 1 decimal en Miles de Millones
    Etiqueta = ifelse(Tipo == "Sector", 
                      sprintf("%.2f Bill", Valor / 1e12), 
                      sprintf("%.1f M mill", Valor / 1e9)),
    X_Num = ifelse(Tipo == "Sector", 1, 2)
  )

# 4. Cálculo de Variación para el Tooltip
resumen_costo <- costo_plot %>%
  group_by(Tipo) %>%
  summarize(
    crecimiento_pct = (Valor[Año == 2025] - Valor[Año == 2023]) / Valor[Año == 2023] * 100,
    y_vis_max = max(Valor_Vis)
  ) %>%
  mutate(
    X_Num = ifelse(Tipo == "Sector", 1, 2),
    Label_Text = paste0("Δ ", round(crecimiento_pct, 1), "%")
  )

# 5. Generación del Gráfico Final
ggplot(costo_plot, aes(x = X_Num, y = Valor_Vis, fill = factor(Año))) +
  annotate("rect", xmin = 1.5, xmax = 2.5, ymin = 0, ymax = Inf, fill = "#F0F7FB", alpha = 0.3) +
  
  geom_col(position = position_dodge(width = 0.8), width = 0.7, color = "white", linewidth = 0.1) +
  
  # Tooltips de Variación Δ %
  geom_text(data = resumen_costo, 
            aes(x = X_Num, y = y_vis_max * 1.12, label = Label_Text),
            inherit.aes = FALSE, size = 3.5, fontface = "bold", color = "#E67E22") +
  
  geom_segment(data = resumen_costo,
               aes(x = X_Num - 0.2, xend = X_Num + 0.2, y = y_vis_max * 1.05, yend = y_vis_max * 1.05),
               inherit.aes = FALSE, color = "#AEB6BF", linewidth = 0.3) +

  # Etiquetas de datos con la nueva precisión (Sector: 0.00 Bill)
  geom_text(aes(label = Etiqueta), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 3, color = "grey20", fontface = "bold") +
  
  scale_x_continuous(breaks = c(1, 2), labels = c("SECTOR", "UNIMOS")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.2)), labels = NULL, name = NULL) +
  scale_fill_manual(values = c("2023" = "#D5DBDB", "2024" = "#5D6D7E", "2025" = "#E67E22"), name = NULL) +
  
  labs(title = "Eficiencia Operativa: Costo de Ventas", 
       subtitle = "Seguimiento detallado 2023-2025 (Precisión de dos decimales para el Sector)") +
  theme_void() +
  theme(
    plot.margin = margin(20, 20, 20, 20),
    plot.title = element_text(face = "bold", size = 13, hjust = 0.5, color = "#2C3E50"),
    plot.subtitle = element_text(size = 10, hjust = 0.5, color = "#7F8C8D", margin = margin(b = 20)),
    axis.text.x = element_text(size = 10, face = "bold", color = "#2C3E50", margin = margin(t = 10)),
    legend.position = "bottom"
  )

Conclusiones

  • La cooperativa ha logrado reducir su costo de ventas en un -5.8% de manera acumulada. La gestión interna ha permitido absorber el crecimiento de la operación sin disparar los costos directos.

  • Mantener los costos en el rango de los 3.8 M mill mientras los ingresos y la cartera crecen es un indicador de que Unimos está logrando economías de escala, optimizando cada peso invertido en la generación de servicios financieros.

  • Esta gráfica es la “explicación técnica” de por qué los excedentes crecieron de forma tan robusta (73.4%). Al lograr que el Costo de Ventas baje mientras la actividad comercial sube, la utilidad se expande de manera acelerada.

Excedentes

Code
library(dplyr)
library(readr)
library(ggplot2)

# 1. Carga de datos
Excedente_Unimos <- read_csv("data/Excedente_Unimos.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))
Excedente_Sector <- read_csv("data/Excedente_Sector.csv", 
    col_types = cols(Año = col_character(), `Nombre Mes Corto` = col_skip()))

# 2. Preparación
Excedente_Consolidado <- bind_rows(
  Excedente_Sector %>% mutate(Tipo = "Sector") %>% rename(Valor = `3.5. Excedentes y/o perdidas del ejercicio`),
  Excedente_Unimos %>% mutate(Tipo = "Unimos") %>% rename(Valor = `3.5. Excedentes y/o perdidas del ejercicio`)
) %>% mutate(Año = as.numeric(Año))

# 3. AJUSTE DE ESCALA VISUAL
# Reducimos de 500 a 200 para que el Sector gane peso visual
f_escala_proporcional <- 200  

excedente_plot <- Excedente_Consolidado %>%
  mutate(
    Valor_Vis = ifelse(Tipo == "Unimos", Valor * f_escala_proporcional, Valor),
    Etiqueta = ifelse(Tipo == "Sector", 
                      paste0(round(Valor / 1e9, 1), " M mill"), 
                      paste0(round(Valor / 1e6, 0), " Mill")),
    X_Num = ifelse(Tipo == "Sector", 1, 2)
  )

# 4. Resumen para Tooltip
resumen_exc <- excedente_plot %>%
  group_by(Tipo) %>%
  summarize(
    crecimiento_pct = (Valor[Año == 2025] - Valor[Año == 2023]) / Valor[Año == 2023] * 100,
    y_vis_max = max(Valor_Vis)
  ) %>%
  mutate(
    X_Num = ifelse(Tipo == "Sector", 1, 2),
    Label_Text = paste0("Δ ", round(crecimiento_pct, 1), "%")
  )

# 5. Gráfico con Proporción Corregida
ggplot(excedente_plot, aes(x = X_Num, y = Valor_Vis, fill = factor(Año))) +
  # Sombra para Unimos
  annotate("rect", xmin = 1.5, xmax = 2.5, ymin = 0, ymax = Inf, fill = "#F0F7FB", alpha = 0.3) +
  
  geom_col(position = position_dodge(width = 0.8), width = 0.7, color = "white", linewidth = 0.1) +
  
  # Tooltips
  geom_text(data = resumen_exc, 
            aes(x = X_Num, y = y_vis_max * 1.12, label = Label_Text),
            inherit.aes = FALSE, size = 3.5, fontface = "bold", color = "#566573") +
  geom_segment(data = resumen_exc,
               aes(x = X_Num - 0.2, xend = X_Num + 0.2, y = y_vis_max * 1.05, yend = y_vis_max * 1.05),
               inherit.aes = FALSE, color = "#AEB6BF", linewidth = 0.3) +

  # Etiquetas de datos
  geom_text(aes(label = Etiqueta), 
            position = position_dodge(width = 0.8), 
            vjust = -0.5, size = 3, color = "grey20", fontface = "bold") +
  
  scale_x_continuous(breaks = c(1, 2), labels = c("SECTOR", "UNIMOS")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.2))) +
  scale_fill_manual(values = c("2023" = "#D5DBDB", "2024" = "#5D6D7E", "2025" = "#E67E22"), name = NULL) +
  
  labs(title = "Rentabilidad: Excedentes del Ejercicio (3.5)", 
       subtitle = "Escalas visuales ajustadas para destacar la magnitud del Sector") +
  theme_void() +
  theme(
    plot.margin = margin(20, 20, 20, 20),
    plot.title = element_text(face = "bold", size = 13, hjust = 0.5, color = "#2C3E50"),
    plot.subtitle = element_text(size = 10, hjust = 0.5, color = "#7F8C8D", margin = margin(b = 20)),
    axis.text.x = element_text(size = 10, face = "bold", color = "#2C3E50", margin = margin(t = 10)),
    legend.position = "bottom"
  )