GAA1104 · Big Data e Inteligencia de Negocios · Clase 19

Reporte 1: el panel de EEFF en Power BI

Tienes el modelo estrella del panel cargado en Power BI, las cuatro medidas financieras base calzando con SQL, y la historia del semestre visible en tres visuales.

El notebook de esta clase: https://gaa1104.vercel.app/notebooks/clase-19.ipynb

Ing. en Administración · mención Finanzas · Prof. Tomás Fernández

Clase 19 · el gráfico de hoy

Barras por sector, y línea para la serie

Margen por sector es magnitud comparada; su evolución es tiempo. Dos gráficos, un eje cada uno.

La forma la decide el trabajo que hace el dato —magnitud, identidad, polaridad, cambio en el tiempo, distribución—, no el gusto. Regla del curso: un solo eje.

Apertura — Active recall · 8 min

Lo que quedó planteado ayer (se proyecta la pregunta, NO la respuesta):

«La página se ve bien. ¿De dónde sale cada número? ¿Hay un modelo detrás o son 1.109 filas planas?»

Tres preguntas, en silencio, 90 segundos (espaciado 1–3–7–21):

Apertura — Active recall · 8 min
  1. De ayer: ¿cuántas barras devolvió el GROUP BY sector y cuántos sectores hay de verdad?
  2. De la sesión 26 (hace tres clases): ¿qué llevaba la recomendación de la etapa 3, además del hallazgo?
  3. De la sesión 18 (hace más de siete clases, Anki): ¿qué es la prueba de suma cruzada y qué separa exactamente?

Par (2 min) → plenaria (3 min).

Apertura — Active recall · 8 min

Se responde la pregunta colgada CON ellos. La respuesta se construye y se escribe:

Hoy son 1.109 filas planas. Y por eso la página de ayer no se puede auditar: si el CFO pregunta de dónde sale el 34,5 %, la respuesta es «de un gráfico». Un modelo convierte esa respuesta en una cadena: la medida sale del hecho, el hecho se une a la dimensión por una llave, y la llave es el RUT. Eso es lo que se construye hoy.
Apertura — Active recall · 8 min

Preguntas que quedan planteadas hoy — se escriben ahora en la pizarra y no se responden hoy: se retoman mañana en la apertura.

El modelo del panel, construido en SQL y heredado por Power BI · 28 min

El grano se declara por escrito antes de la primera consulta. En la pizarra, con esas palabras:

Una fila de fact_eeff es una empresa en un trimestre. 40 empresas × 28 trimestres = 1.120 posibles; hay 1.109.

Las dimensiones se generan en DuckDB y se exportan. Power BI hereda el modelo, no lo inventa — y esa frase se dice en voz alta porque es la diferencia entre un analista y un usuario de herramienta.

El modelo del panel, construido en SQL y heredado por Power BI · 28 min

👀 Se mira — las dos vistas de partida

Vienen resueltas: se corren y se lee la salida.

El modelo del panel, construido en SQL y heredado por Power BI · 28 min
-- 👀 SE MIRA · la vista que limpia texto y abre el trimestre en año y Q
CREATE OR REPLACE VIEW eeff AS
SELECT periodo,
       trimestre,
       CAST(left(trimestre, 4) AS INTEGER)            AS anio,
       right(trimestre, 2)                            AS q,
       replace(rut, '.', '')                          AS rut_n,
       trim(regexp_replace(empresa, ' +', ' ', 'g'))  AS empresa_n,
       upper(strip_accents(trim(sector)))             AS sector_n,
       * EXCLUDE (periodo, trimestre, rut, empresa, sector)
FROM read_csv_auto('datos/finanzas/eeff_empresas.csv');
El modelo del panel, construido en SQL y heredado por Power BI · 28 min

Y el maestro, que es el que trae los nombres limpios:

-- 👀 SE MIRA · el maestro, que es el que trae los nombres limpios
CREATE OR REPLACE VIEW catalogo AS
SELECT u.rut, u.razon_social, u.sector, u.reporta_en
FROM (SELECT UNNEST(empresas) AS u
      FROM read_json_auto('datos/finanzas/catalogo_empresas.json', maximum_depth = -1));

El momento de la sesión, antes de exportar nada. Se corre esto y se deja en pantalla:

El modelo del panel, construido en SQL y heredado por Power BI · 28 min
-- 👀 SE MIRA · el momento de la sesión: 200 formas, 137 tras limpiar, 40 empresas
SELECT COUNT(DISTINCT empresa)                                    AS formas_en_bruto,
       COUNT(DISTINCT trim(regexp_replace(empresa,' +',' ','g')))  AS formas_tras_limpiar,
       COUNT(DISTINCT replace(rut, '.', ''))                      AS empresas_reales
FROM read_csv_auto('datos/finanzas/eeff_empresas.csv');
-- 200 | 137 | 40
El modelo del panel, construido en SQL y heredado por Power BI · 28 min
200 formas de escritura. Limpias los espacios como buen alumno, y te quedan 137. Empresas hay 40.

«Normalizar texto hasta que se vea bien es lo que hace casi todo el mundo, y deja 137 empresas donde hay 40. El punto final de S.A.. no lo borra ningún trim. Se agrupa por RUT y el nombre bonito se saca del catálogo. Esa frase la van a repetir el resto de su carrera.»
El modelo del panel, construido en SQL y heredado por Power BI · 28 min

Las cuatro tablas, exportadas con las sentencias que ya corrieron:

El modelo del panel, construido en SQL y heredado por Power BI · 28 min
COPY (SELECT replace(c.rut, '.', '') AS rut_n, c.rut, c.razon_social, c.sector, c.reporta_en
      FROM catalogo c ORDER BY 1)
TO 'salidas/dim_empresa.csv' (HEADER);                       -- 40 filas

COPY (SELECT DISTINCT trimestre,
             CAST(left(trimestre, 4) AS INTEGER) AS anio,
             right(trimestre, 2)                 AS q,
             CAST(periodo AS DATE)               AS fecha_cierre
      FROM eeff ORDER BY fecha_cierre)
TO 'salidas/dim_tiempo.csv' (HEADER);                        -- 28 filas
El modelo del panel, construido en SQL y heredado por Power BI · 28 min

Y la de sector, que sale del maestro y no del CSV:

COPY (SELECT DISTINCT sector AS sector_nombre,
             upper(strip_accents(trim(sector))) AS sector_n
      FROM catalogo ORDER BY 2)
TO 'salidas/dim_sector.csv' (HEADER);                        -- 6 filas

Y el hecho, con las 16 columnas que se van al modelo:

El modelo del panel, construido en SQL y heredado por Power BI · 28 min
COPY (SELECT rut_n, trimestre, ingresos_mm_clp, costo_venta_mm_clp,
             gastos_operacionales_mm_clp, ebitda_mm_clp, depreciacion_mm_clp,
             resultado_operacional_mm_clp, gastos_financieros_mm_clp, utilidad_neta_mm_clp,
             activos_totales_mm_clp, activos_corrientes_mm_clp, pasivos_corrientes_mm_clp,
             deuda_financiera_mm_clp, patrimonio_mm_clp, empleados
      FROM eeff)
TO 'salidas/fact_eeff.csv' (HEADER);                         -- 1.109 filas
El modelo del panel, construido en SQL y heredado por Power BI · 28 min

Ojo con la dim_sector: sale de catalogo, no del CSV. Del CSV salían 25 filas (lo de ayer). Del catálogo salen 6. La dimensión limpia vive en el maestro; el hecho trae la suciedad. Eso es la regla del curso, no una casualidad de este archivo.

El modelo del panel, construido en SQL y heredado por Power BI · 28 min
Por qué la clase se dicta en Power BI si acá la herramienta ya es libre. Se dice en una frase, sin abrir debate: «se dicta en Power BI porque ustedes acaban de armar un modelo ahí y hoy lo que se aprende es a heredarlo, no a aprender una herramienta nueva. Pero desde este bloque el instrumento dice «Power BI (o herramienta de BI equivalente)»: el que quiera hacer este mismo panel en Looker Studio puede, y el puente es bd.a_sheets() desde Colab. Las cuatro medidas, la verificación cruzada y la página son idénticas — cambia dónde se aprietan los botones, no lo que se evalúa.» Regla escrita en recursos/herramienta-de-bi.md; el camino completo, en recursos/guia-looker-estudiante.md.
El modelo del panel, construido en SQL y heredado por Power BI · 28 min

🔨 Actividad — El modelo estrella, cargado y verificado

Entregas: las cuatro tablas cargadas con relaciones dim → fact en 1:*, dim_tiempo marcada como tabla de fechas, y la verificación de integridad corrida con su número anotado: 1.109 · 1.109 · 0 huérfanas. Dentro de los 28 minutos de este bloque.

El modelo del panel, construido en SQL y heredado por Power BI · 28 min

En Power BI: cargar las cuatro tablas, relaciones dim → fact en 1:*, dim_tiempo marcada como tabla de fechas. Verificación en la vista de modelo: tiene que verse una estrella con el hecho al centro. Si Power BI dibujó una relación muchos-a-muchos, la dimensión está mal construida y se rehace — no se le pone «ambos» a la dirección del filtro para tapar el problema.

La verificación de integridad, obligatoria y anotada:

El modelo del panel, construido en SQL y heredado por Power BI · 28 min
-- 🔨 ACTIVIDAD · córrela y anota el resultado: tiene que dar cero huérfanas
SELECT COUNT(*)                AS filas_del_hecho,
       COUNT(c.rut)            AS filas_con_maestro,
       COUNT(*) - COUNT(c.rut) AS huerfanas
FROM eeff e
LEFT JOIN catalogo c ON replace(c.rut, '.', '') = e.rut_n;
-- 1109 | 1109 | 0
El modelo del panel, construido en SQL y heredado por Power BI · 28 min

Cero huérfanas. Y se dice por qué salió cero: porque la unión va por RUT normalizado. Si fuera por nombre, con 200 formas contra 40 razones sociales, la mitad del panel se caía en silencio.

Las cuatro medidas del oficio · encuadre · 9 min

No son cuatro fórmulas: son las cuatro preguntas que un directorio hace siempre, en este orden.

Las cuatro medidas del oficio · encuadre · 9 min
MedidaLa pregunta que respondeCuidado
Margen EBITDA = EBITDA / ingresos¿El negocio operativo gana plata?Sólo comparable dentro del mismo sector
ROE = utilidad neta 12 m / patrimonio promedio de los 4 trimestres (suma ÷ 4, no AVERAGE)¿Le rinde al dueño?Cae por operación o por deuda: hay que separar
Deuda / EBITDA¿Cuántos años de EBITDA debe?Tiene numerador y denominador; mañana la clase entera
Liquidez corriente = act. corrientes / pas. corrientes¿Paga lo de este año con lo de este año?Bajo no es malo: Utilities vive en 1,18 y está sana
Respiro · 5 min

Pararse, estirar, subir la luz un segundo. Clase nocturna: el cuerpo también aprende. Se reanuda 21:20.

Las medidas en DAX, y la verificación cruzada · 30 min

🔨 Actividad — Las cuatro medidas, y que calcen con SQL

Entregas: las cuatro medidas escritas en tu herramienta y el margen EBITDA calzando contra SQL en al menos dos sectores, celda por celda. 30 minutos.

Se escriben en Power BI, una por una, proyectadas y copiadas:

Las medidas en DAX, y la verificación cruzada · 30 min
Ingresos = SUM(fact_eeff[ingresos_mm_clp])
EBITDA   = SUM(fact_eeff[ebitda_mm_clp])

Margen EBITDA % = DIVIDE([EBITDA], [Ingresos])

Y sobre ésas, los tres ratios que pide el caso:

Las medidas en DAX, y la verificación cruzada · 30 min
Patrimonio promedio = DIVIDE(SUM(fact_eeff[patrimonio_mm_clp]), 4)

ROE % = DIVIDE(SUM(fact_eeff[utilidad_neta_mm_clp]), [Patrimonio promedio])

Deuda cierre = CALCULATE(SUM(fact_eeff[deuda_financiera_mm_clp]),
                         dim_tiempo[q] = "Q4")

Deuda / EBITDA = DIVIDE([Deuda cierre], [EBITDA])

Liquidez = DIVIDE(SUM(fact_eeff[activos_corrientes_mm_clp]),
                  SUM(fact_eeff[pasivos_corrientes_mm_clp]))
Las medidas en DAX, y la verificación cruzada · 30 min

CALCULATE se presenta en una frase y con un solo uso: es el WHERE de DAX. Nada más hoy.

Verificación cruzada en vivo — el hábito de siempre, ahora en la herramienta. Se pone la matriz de margen EBITDA por sector y año en Power BI y se compara contra SQL, celda por celda, en dos sectores:

Las medidas en DAX, y la verificación cruzada · 30 min
-- 🔨 ACTIVIDAD · ésta es la vara: tu matriz de Power BI tiene que dar esto mismo
SELECT sector_n, anio,
       ROUND(100.0 * SUM(ebitda_mm_clp) / SUM(ingresos_mm_clp), 1) AS margen_ebitda_pct
FROM eeff
WHERE rut_n <> '76660573-7'
GROUP BY 1, 2
ORDER BY 1, 2;
-- UTILITIES  2019 35.8 · 2021 34.7 · 2023 34.5 · 2025 35.3
-- RETAIL     2019  9.2 · 2021  8.1 · 2023  7.5 · 2025  8.0
Las medidas en DAX, y la verificación cruzada · 30 min

Si Power BI no da lo mismo, hay exactamente tres sospechosos y se revisan en este orden: 1 · el filtro de la empresa que reporta en dólares no está puesto en la medida; 2 · la relación quedó en dirección cruzada; 3 · alguien sumó porcentajes en vez de dividir sumas. El tercero es el más frecuente y el más caro: el promedio de los márgenes no es el margen del promedio.

Las medidas en DAX, y la verificación cruzada · 30 min

Y hay un cuarto, que sólo muerde en el ROE y por eso se dice ahora: AVERAGE en DAX divide por el número de filas del contexto, no por 4. En la tarjeta de una empresa hay 4 filas al año y da lo correcto; en la matriz por sector hay 4 trimestres × N empresas, el denominador queda N veces más chico y el ROE sale multiplicado por N. Utilities tiene 7 empresas: con AVERAGE, 2021 daría 64,2 % en vez de 9,2 % — siete veces el número, y en una lámina que nadie va a revisar. Por eso el patrimonio promedio se escribe como medida propia, suma ÷ 4, y el ROE la usa a ella. La verificación cruzada contra SQL es la que lo caza:

Las medidas en DAX, y la verificación cruzada · 30 min
SELECT anio,
       ROUND(100.0 * SUM(utilidad_neta_mm_clp)
                   / (SUM(patrimonio_mm_clp) / 4.0), 1) AS roe_pct
FROM eeff
WHERE sector_n = 'UTILITIES'
GROUP BY 1
ORDER BY 1;
-- 2019 9.2 · 2021 9.2 · 2023 5.3 · 2025 7.7
El experto de negocio interno · 10 min

La duda concreta del dato de hoy: al construir dim_tiempo con 28 trimestres, tres empresas no tienen las 28 filas.

El experto de negocio interno · 10 min
WITH todos AS (SELECT DISTINCT trimestre FROM eeff),
     emp   AS (SELECT rut_n, any_value(empresa_n) AS empresa FROM eeff GROUP BY 1)
SELECT emp.empresa,
       COUNT(*)                               AS trimestres_ausentes,
       list(t.trimestre ORDER BY t.trimestre) AS cuales
FROM emp
CROSS JOIN todos t
LEFT JOIN eeff x ON x.rut_n = emp.rut_n AND x.trimestre = t.trimestre
WHERE x.trimestre IS NULL
GROUP BY 1
ORDER BY 2 DESC;
-- Caja Crédito Pacífico S.A.  | 4 | [2024-Q3, 2024-Q4, 2025-Q1, 2025-Q2]
-- Clínica Puerto Varas SpA    | 4 | [2019-Q1, 2019-Q2, 2019-Q3, 2019-Q4]
-- Forestal Chiloé SpA.        | 3 | [2021-Q2, 2021-Q3, 2023-Q1]
El experto de negocio interno · 10 min

A quién se le pregunta: Relación con Inversionistas (o Fiscalía, si es una empresa que dejó de reportar). La pregunta textual:

«¿Falta ese trimestre, o la empresa todavía no existía / dejó de reportar?»

Y por qué cambia todo: los tres casos se ven idénticos en el CSV y son tres cosas distintas.

El experto de negocio interno · 10 min
El experto de negocio interno · 10 min
Una serie de tiempo con hoyos miente con gráfico bonito: la línea los une y el ojo ve continuidad donde no hay dato. En la página, los trimestres ausentes se marcan; no se interpolan.

Es el mismo diagnóstico de la sesión 07 con las 639 líneas de Austral sin fecha de pago: la misma celda vacía, tres diagnósticos opuestos. Por eso se pregunta antes de imputar.

La historia del semestre en tres visuales · 20 min

🔨 Actividad — Los tres visuales de tu página 1

Entregas: los tres visuales armados en tu página 1, cada uno con un solo eje, sus unidades escritas y la frase que lo lee. 20 minutos.

Cada uno la arma en su página 1. Son tres frases y sus tres evidencias. Los gráficos de abajo vienen resueltos: se corren para ver la forma que hay que reproducir en la herramienta.

1 · «Los ingresos volvieron después de 2020.»

La historia del semestre en tres visuales · 20 min
SELECT anio, ROUND(SUM(ingresos_mm_clp) / 1e6, 2) AS ingresos_billones_clp
FROM eeff WHERE rut_n <> '76660573-7'
GROUP BY 1 ORDER BY 1;
-- 2019 16.60 · 2020 16.49 · 2021 19.81 · 2022 23.03 · 2023 23.39 · 2024 24.33 · 2025 26.16

2 · «Y aun así, el margen EBITDA no recuperó el nivel de 2019 en ningún sector.» Pequeños múltiplos, seis paneles, escala común. Utilities 35,8 → 34,5 en 2023; Retail 9,2 → 7,5; Salud 15,5 → 13,7. Volvió la venta, no volvió el margen: el costo subió más rápido que el precio.

La historia del semestre en tres visuales · 20 min

Antes de armarla en Power BI, se dibuja acá. Es la misma consulta de las 21:20, ahora con la forma puesta: seis sectores comparados en una sola medida es magnitud comparada, y eso son barras. Horizontales, porque los nombres de sector son largos, y ordenadas por valor.

La historia del semestre en tres visuales · 20 min
# 👀 SE MIRA · el gráfico ya viene escrito: se corre y se mira la forma
import matplotlib.pyplot as plt

GRIS, TINTA, ALERTA = "#b8b8b8", "#102a38", "#8c2b20"

m = bd.sql("""
  SELECT sector_n,
         ROUND(100.0 * SUM(ebitda_mm_clp)   FILTER (WHERE anio = 2019)
                     / SUM(ingresos_mm_clp) FILTER (WHERE anio = 2019), 1) AS m2019,
         ROUND(100.0 * SUM(ebitda_mm_clp)   FILTER (WHERE anio = 2023)
                     / SUM(ingresos_mm_clp) FILTER (WHERE anio = 2023), 1) AS m2023
  FROM eeff WHERE rut_n <> '76660573-7'
  GROUP BY 1 ORDER BY m2023""")

fig, eje = plt.subplots(figsize=(9.5, 5))
y = range(len(m))
eje.barh([v + 0.20 for v in y], m.m2019, height=0.38, color=GRIS,   label="2019")
eje.barh([v - 0.20 for v in y], m.m2023, height=0.38, color=ALERTA, label="2023")
eje.set_yticks(list(y))
eje.set_yticklabels(m.sector_n, fontsize=10)

for i, (a, b) in enumerate(zip(m.m2019, m.m2023)):
    eje.text(a + 0.4, i + 0.20, f"{a:.1f}".replace(".", ","),
             va="center", fontsize=9, color="#767676")
    eje.text(b + 0.4, i - 0.20, f"{b:.1f}".replace(".", ","),
             va="center", fontsize=9, color=ALERTA)

eje.set_title("Volvió la venta, no volvió el margen: los seis sectores cierran 2023\n"
              "bajo su margen EBITDA de 2019",
              fontsize=13, color=TINTA, loc="left")
eje.set_xlabel("margen EBITDA (EBITDA ÷ ingresos, en %)", fontsize=9)
eje.set_xlim(0, 40)
eje.legend(frameon=False, fontsize=9, loc="lower right")
for lado in ("top", "right", "left"):
    eje.spines[lado].set_visible(False)
eje.tick_params(length=0)
fig.tight_layout()
plt.show()
La historia del semestre en tres visuales · 20 min

Qué se mira: las seis parejas apuntan para el mismo lado, y eso es el hallazgo — no el nivel de cada sector. Utilities baja de 35,8 a 34,5 y Retail de 9,2 a 7,5: distancias parecidas en puntos, negocios incomparables entre sí. Por eso el margen EBITDA sólo se compara dentro del mismo sector, y por eso este gráfico no ordena a los sectores para premiar a nadie.

3 · «Los gastos financieros se triplican entre 2021 y 2023 sin que la deuda se triplique.»

La historia del semestre en tres visuales · 20 min
SELECT anio,
       SUM(gastos_financieros_mm_clp)                       AS gastos_financieros_mm,
       SUM(deuda_financiera_mm_clp) FILTER (WHERE q = 'Q4') AS deuda_cierre_mm,
       ROUND(100.0 * 4 * SUM(gastos_financieros_mm_clp)
                       / SUM(deuda_financiera_mm_clp), 2)   AS tasa_implicita_pct
FROM eeff
GROUP BY 1
ORDER BY 1;
-- 2021 |   520.955 | 12.089.286 |  4,32 %
-- 2023 | 1.651.271 | 14.565.551 | 11,46 %
La historia del semestre en tres visuales · 20 min
El gasto financiero se multiplica por 3,17 y la deuda sube 20,5 %. No se endeudaron más: les subieron el precio del dinero. Esa distinción, hecha con dos columnas, es la diferencia entre un informe que describe y uno que explica.
La historia del semestre en tres visuales · 20 min

Y acá está la trampa que esta clase tiene que no caer. Hay dos series —gastos financieros y deuda— y la tentación es ponerlas juntas con dos ejes, uno a cada lado. No se hace, nunca, y ésta es la clase donde se demuestra por qué: con dos ejes uno elige la escala hasta que las líneas cuenten lo que uno quiera. La salida honesta es indexar las dos a una base común y dejar un solo eje. La base la elige el análisis: 2021, que es el año desde el que se hace la afirmación.

La historia del semestre en tres visuales · 20 min
# 👀 SE MIRA · dos magnitudes distintas en un solo eje: la salida honesta
import matplotlib.pyplot as plt

GRIS, TINTA, ALERTA = "#b8b8b8", "#102a38", "#8c2b20"

s = bd.sql("""
  SELECT anio,
         SUM(gastos_financieros_mm_clp)                       AS gastos_financieros,
         SUM(deuda_financiera_mm_clp) FILTER (WHERE q = 'Q4') AS deuda_cierre
  FROM eeff GROUP BY 1 ORDER BY 1""")
base = s[s.anio == 2021].iloc[0]

gf = 100 * s.gastos_financieros / base.gastos_financieros
dc = 100 * s.deuda_cierre / base.deuda_cierre

fig, eje = plt.subplots(figsize=(9.5, 4.6))
eje.plot(s.anio, dc, color=GRIS,   linewidth=2.2, marker="o",
         label="deuda financiera de cierre")
eje.plot(s.anio, gf, color=ALERTA, linewidth=2.4, marker="o",
         label="gastos financieros del año")
eje.axhline(100, color=TINTA, linewidth=0.8, linestyle="--")
eje.text(2019, 104, "base 2021 = 100", fontsize=9, color=TINTA)

i2023 = list(s.anio).index(2023)
eje.annotate(f"{gf.iloc[i2023]:.0f}", xy=(2023, gf.iloc[i2023]), xytext=(6, -2),
             textcoords="offset points", fontsize=11, color=ALERTA)
eje.annotate(f"{dc.iloc[i2023]:.0f}", xy=(2023, dc.iloc[i2023]), xytext=(6, -2),
             textcoords="offset points", fontsize=11, color="#767676")

eje.set_title("No se endeudaron más: les subieron el precio del dinero.\n"
              "Entre 2021 y 2023 el gasto financiero se multiplica por 3,17 y la deuda sube 20,5 %",
              fontsize=13, color=TINTA, loc="left")
eje.set_ylabel("índice, 2021 = 100", fontsize=9)
eje.set_xticks(list(s.anio))
eje.legend(frameon=False, fontsize=9, loc="upper left")
for lado in ("top", "right"):
    eje.spines[lado].set_visible(False)
fig.tight_layout()
plt.show()
La historia del semestre en tres visuales · 20 min

Qué se mira en el resultado:

  1. Las dos líneas parten pegadas en 100 y se abren. Eso es todo el mensaje, y sólo se ve porque están indexadas: en pesos, la deuda es más de veinte veces más grande que el gasto financiero y la línea del gasto habría quedado aplastada contra el eje.
  2. 317 contra 120. El gasto financiero por 3,17; la deuda, 20,5 % más. La diferencia entre esos dos números es la tasa.
La historia del semestre en tres visuales · 20 min

Y si sobran dos minutos, se comprueba en vez de afirmarse. Hasta acá la tasa es una deducción: el gasto creció mucho más que la deuda, luego subió el precio del dinero. Es correcto, y además se puede verificar — el Banco Central publica la serie.

La historia del semestre en tres visuales · 20 min
SELECT year,
       ROUND(cbrate, 2)      AS tpm_promedio_del_anio,
       ROUND(infl, 1)        AS inflacion,
       ROUND(govdebt_GDP, 1) AS deuda_publica_pct_pib
FROM macro
WHERE ISO3 = 'CHL' AND year BETWEEN 2019 AND 2024
ORDER BY year;
-- 2020: TPM 0,50 · 2022: TPM 11,25 · 2024: TPM 5,00
La historia del semestre en tres visuales · 20 min
«La tasa de política monetaria pasó de 0,50 % en 2020 a 11,25 % en 2022. Veintidós veces. Las
empresas del panel no se endeudaron veintidós veces más: pagaron veintidós veces más caro lo mismo.
Eso es lo que dice el visual 3, y recién ahora lo dice con el dato al lado.»
La historia del semestre en tres visuales · 20 min

Lo que hay que decir, porque es la lección del bloque completo: el panel de la empresa no explica el panel de la empresa. Un analista que sólo mira el estado de resultados concluye mala gestión financiera y recomienda cambiar al tesorero. El que mira el país al lado concluye ciclo de tasas y recomienda otra cosa. Los dos leyeron el mismo número.

Fuente: Global Macro Data (globalmacrodata.com), serie cbrate para Chile. La tabla macro la carga bd.macro(); en la consola del profesor viene con cargar.sql.

La historia del semestre en tres visuales · 20 min
  1. El rótulo del eje: «índice, 2021 = 100». Sin ese rótulo el gráfico es un truco. Con él, es la única manera honesta de poner dos magnitudes de tamaño distinto en un mismo eje — y es la respuesta que hay que dar cuando alguien pida el segundo eje.
Síntesis y ticket · 10 min

Construida con ellos:

Síntesis y ticket · 10 min
  1. «¿Por qué agrupamos por RUT y no por nombre?» → 200 formas, 137 después de limpiar, 40 empresas.
  2. «¿De dónde salió la dimensión de sector limpia?» → del catálogo, no del CSV.
  3. «¿Qué revisas si Power BI y SQL no dan lo mismo?» → filtro, dirección de relación, promedio de porcentajes.
  4. «¿Qué hacemos con los 11 trimestres ausentes?» → preguntar antes de rellenar.
Síntesis y ticket · 10 min

Ticket T29 (3 min, adaptado al panel): a) ¿Qué hace CALCULATE? Una frase. b) Tu margen EBITDA de Utilities y de Retail en 2023: los números, de memoria. c) Del 1 al 5, dónde te sientes y qué te falta.

Preguntas que quedan planteadas (se escriben en la pizarra y no se responden hoy):

Síntesis y ticket · 10 min
→ Utilities pierde 4 puntos de ROE entre 2021 y 2023 (9,2 % → 5,3 %) con el margen EBITDA prácticamente intacto (34,7 % → 34,5 %). ¿Empeoró el negocio?

→ Si un ratio empeora, ¿cómo sabes si fue el numerador o el denominador?
Clase 19 · cierre

Ticket de salida

Tres minutos. No suma nota. Sirve para armar la apertura de la próxima clase.

El notebook de esta clase:
https://gaa1104.vercel.app/notebooks/clase-19.ipynb

← → avanzar · P proyector · F pantalla completa
GAA1104 · C19 · Reporte 1: el panel de EEFF en Power BI 20:30 1 / 1