GAA1104 · Big Data e Inteligencia de Negocios · Clase 05

Calidad completa: qué está roto y qué está vivo (+ Control C2)

Distingues un vacío legítimo de un error de captura con evidencia, defines qué es un valor "raro" con un criterio reproducible (IQR) en vez de con tu opinión, y separas el error de la información legítima del negocio con una matriz que puedes defender — la competencia central del Parcial 1.

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

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

Clase 05 · el gráfico de hoy

Diagrama de caja

La pregunta es de distribución: dónde está el grueso y qué queda afuera. Es el IQR de la clase dibujado, y los puntos sueltos son los atípicos que hay que decidir si son error o negocio.

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 la clase anterior (se proyecta la pregunta, NO la respuesta):

«639 líneas sin fecha de pago. ¿Es un error del archivo o es plata en la calle?»

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

Apertura — Active recall · 8 min
  1. (clase 04) ¿Por qué es más peligrosa una conversión de fecha que no falla que una que sí falla? Da el número de filas.
  2. (clase 04) De los 18 RUT distintos, sólo 3 pasaron la validación por módulo 11. ¿Qué controla exactamente ese cálculo, y por qué se corre antes de salir a buscar datos y no después?
  3. (clase 01) ¿Qué hace que una planilla deje de servir: el volumen o la forma? ¿Y por qué la diferencia importa para el presupuesto?
Apertura — Active recall · 8 min

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

La pregunta colgada se responde con ellos, y la respuesta es el título de la clase:

«Es plata en la calle. Y para saberlo no bastó mirar la celda vacía: hubo que preguntarse qué representa esa columna cuando está vacía. Hoy vamos a hacer eso mismo cuatro veces, y dos de las cuatro van a dar el resultado contrario.»
Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min

Primero el mapa completo, para no discutir sobre impresiones. Se pega el arranque de siempre (30 segundos, está en el .sql del sitio del curso):

Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min
CREATE OR REPLACE TABLE ventas AS
SELECT * FROM read_csv_auto('datos/finanzas/ventas_extracto.csv');

CREATE OR REPLACE VIEW v AS
SELECT *,
       COALESCE(TRY_CAST(fecha_emision AS DATE),
                TRY_STRPTIME(fecha_emision, '%d/%m/%Y')::DATE) AS emision,
       TRY_CAST(fecha_vencimiento AS DATE) AS vencimiento,
       TRY_CAST(fecha_pago AS DATE)        AS pago
FROM ventas;
Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min
SELECT COUNT(*) AS lineas,
       COUNT(*) FILTER (WHERE fecha_pago IS NULL)  AS sin_fecha_de_pago,
       COUNT(*) FILTER (WHERE tipo_cambio IS NULL) AS sin_tipo_de_cambio,
       COUNT(*) FILTER (WHERE precio_unitario = 0) AS precio_cero,
       COUNT(*) FILTER (WHERE cantidad < 0)        AS cantidad_negativa,
       COUNT(*) FILTER (WHERE costo_unitario = 0)  AS costo_cero
FROM ventas;
-- 6000 | 639 | 89 | 43 | 109 | 0
Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min
«Ahí está todo lo que falta o parece faltar en el archivo. Cinco columnas, cinco números. Y no se tratan igual. Los cuatro que no son cero se resuelven hoy, y los dos últimos —el precio cero y las cantidades negativas— son los que van a dar vuelta la clase.»

Ahora la evidencia que separa un caso del otro. No se decide por intuición: se mira el patrón.

Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min
SELECT 'fecha_pago vacía' AS columna,
       COUNT(*) AS lineas,
       COUNT(DISTINCT numero_factura) AS facturas,
       MIN(emision) AS emision_mas_antigua,
       MAX(emision) AS emision_mas_reciente
FROM v WHERE fecha_pago IS NULL
UNION ALL
SELECT 'tipo_cambio vacío',
       COUNT(*), COUNT(DISTINCT numero_factura), MIN(emision), MAX(emision)
FROM v WHERE tipo_cambio IS NULL;
-- fecha_pago vacía  | 639 | 324 | 2022-01-12 | 2024-12-26
-- tipo_cambio vacío |  89 |  44 | 2022-01-16 | 2024-11-26
Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min

Los dos diagnósticos, en lámina, uno al lado del otro. Se copia:

Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min
fecha_pago vacíatipo_cambio vacío
Cuántas639 líneas · 324 facturas89 líneas · 44 facturas
¿Qué significa el vacío?la factura todavía no se ha cobradola factura se emitió en USD y nadie anotó el tipo de cambio
¿Es un error?No. Es cartera abierta al corteSí. Es un error de captura del ERP
Tratamientono se imputa nada: se separa como cartera abierta y se reporta apartese rescata desde la fuente externa (Banco Central) y se declara el rescate
Riesgo residualel corte del archivo es diciembre 2024: facturas emitidas en diciembre todavía no vencenel tipo de cambio del Banco Central puede no ser el que usó Contabilidad para esa factura
Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min
«La misma celda vacía, dos diagnósticos opuestos. Y fíjense en lo que hay debajo: 530 de esas 639 líneas son ventas normales sin cobrar, y las otras 109 son notas de crédito, que nunca tienen fecha de pago porque no se cobran, se emiten. Tres poblaciones distintas escondidas en un mismo NULL.

Por eso la regla del curso es preguntar antes de imputar. Rellenar los 639 con una fecha promedio no es limpiar: es fabricar cobranzas que no existieron.»
Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min

Taxonomía en tres líneas, se copia:

Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min
Tipo de faltanteEjemplo de hoyQué se hace
Por diseño (el proceso todavía no ocurrió)cartera abierta: 639 líneasse separa y se informa; no se imputa
Por omisión (alguien no lo cargó)tipo de cambio: 89 líneasse rescata de la fuente y se declara
Por tercero (la fuente externa no lo tiene)15 días sin tipo de cambio en la seriese arrastra el último conocido y se declara
Faltantes con criterio: la misma celda vacía, dos diagnósticos · 18 min

Hilo 2 — dónde vive esto: «El informe de cartera de Tesorería y el estado de resultados de Contabilidad salen del mismo archivo y no cuadran, y no es que uno esté mal: es que uno mira la columna fecha_pago vacía como un activo y el otro la ignora. Cuando te toque explicar esa diferencia en una reunión, esta tabla es tu respuesta.»

Atípicos con IQR, y las 43 líneas a precio cero · 18 min

El problema, planteado primero: «¿Cuál es una venta de línea "anormalmente grande"? Si cada uno pone su umbral, cada informe da un número distinto y ninguno es defendible. Necesitamos un criterio que cualquiera pueda reproducir.»

Construcción guiada, no dictada:

Atípicos con IQR, y las 43 líneas a precio cero · 18 min
-- Decisión declarada: sólo líneas en CLP y con cantidad positiva
-- (las notas de crédito se analizan aparte; mezclarlas ensucia la distribución).
WITH lineas AS (
  SELECT cantidad * precio_unitario AS venta
  FROM ventas WHERE moneda = 'CLP' AND cantidad > 0
)
SELECT ROUND(quantile_cont(venta, 0.25)) AS q1,
       ROUND(quantile_cont(venta, 0.50)) AS mediana,
       ROUND(AVG(venta))                 AS promedio,
       ROUND(quantile_cont(venta, 0.75)) AS q3,
       ROUND(MAX(venta))                 AS maximo
FROM lineas;
-- q1 274.157 | mediana 753.680 | promedio 1.699.630 | q3 1.842.672 | máximo 32.569.096
Atípicos con IQR, y las 43 líneas a precio cero · 18 min

Detenerse en el par promedio–mediana antes de seguir:

«Mediana 753.680. Promedio 1.699.630. El promedio es más del doble de la mediana. Eso no es un error: es la firma de una distribución con cola. La mitad de las líneas vende menos de 754 mil pesos, y el promedio está arrastrado por unas pocas ventas enormes. Si presupuestas la venta del mes multiplicando el promedio por la cantidad de líneas esperada, te vas a equivocar hacia arriba la mayoría de los meses.»
Atípicos con IQR, y las 43 líneas a precio cero · 18 min

Las vallas de Tukey, construidas con ellos, en la pizarra:

Atípicos con IQR, y las 43 líneas a precio cero · 18 min
WITH lineas AS (
  SELECT cantidad * precio_unitario AS venta
  FROM ventas WHERE moneda = 'CLP' AND cantidad > 0
),
qs AS (SELECT quantile_cont(venta, 0.25) AS q1, quantile_cont(venta, 0.75) AS q3 FROM lineas)
SELECT COUNT(*) AS lineas_evaluadas,
       COUNT(*) FILTER (WHERE venta > q3 + 1.5 * (q3 - q1)) AS atipicos_altos,
       ROUND(100.0 * COUNT(*) FILTER (WHERE venta > q3 + 1.5 * (q3 - q1)) / COUNT(*), 2) AS pct
FROM lineas, qs;
-- 5500 | 389 | 7.07
Atípicos con IQR, y las 43 líneas a precio cero · 18 min
«389 líneas atípicas de 5.500. El 7,07 %. Es mucho, y eso también es información: una distribución sana da 1 o 2 %. Un 7 % dice que esta tabla tiene dos poblaciones mezcladas — pedidos normales y pedidos grandes de proyecto.»

Caja y bigotes, leída en voz alta, y el juicio con contexto de negocio:

Atípicos con IQR, y las 43 líneas a precio cero · 18 min
SELECT numero_factura, linea_negocio, descripcion_producto, cantidad,
       ROUND(precio_unitario) AS precio,
       ROUND(cantidad * precio_unitario) AS venta_linea
FROM ventas
WHERE moneda = 'CLP' AND cantidad > 0
ORDER BY cantidad * precio_unitario DESC
LIMIT 5;
-- F-2022-001506 | Herramientas | Sierra circular 7 1/4" | 257 | 126.728 | 32.569.096
-- F-2023-001444 | Herramientas | Sierra circular 7 1/4" | 248 | 130.728 | 32.420.544
-- F-2022-002592 | Herramientas | Sierra circular 7 1/4" | 241 | 120.842 | 29.122.922
-- F-2023-001114 | Herramientas | Sierra circular 7 1/4" | 257 | 113.314 | 29.121.698
-- F-2022-001858 | Herramientas | Sierra circular 7 1/4" | 257 | 112.669 | 28.955.933
Atípicos con IQR, y las 43 líneas a precio cero · 18 min
«257 sierras circulares en una sola línea de factura, a 126 mil pesos cada una. ¿Es error o es verdad? El precio unitario es normal —una sierra circular vale eso—. Lo grande es la cantidad. Y una constructora que equipa una obra compra 250 sierras de una vez.

El atípico no es un error: es el negocio de proyecto. Si lo borras, borras justo la venta que más aporta. Si lo dejas sin marcar, tu promedio miente. La respuesta correcta es separarlo y contarlo aparte, y decirlo en el informe.»
Atípicos con IQR, y las 43 líneas a precio cero · 18 min

Por qué 1,5 y no 2 o 3: es la convención de Tukey. Lo que importa no es el 1,5: es que el criterio sea explícito, escrito y reproducible. Si tu informe dice "se usó q3 + 1,5·IQR sobre las líneas en CLP con cantidad positiva", cualquiera obtiene tus mismos 389. Si dice "se revisaron los valores altos", no obtiene nada.

Y ahora las 43 líneas que revientan cualquier división:

Atípicos con IQR, y las 43 líneas a precio cero · 18 min
SELECT linea_negocio,
       COUNT(*) AS lineas_precio_cero,
       ROUND(AVG(cantidad), 1) AS cantidad_promedio
FROM ventas
WHERE precio_unitario = 0
GROUP BY 1 ORDER BY 2 DESC;
-- Eléctrico    | 13 | 25.2
-- Seguridad    | 11 | 50.3
-- Fijaciones   | 10 | 20.6
-- Herramientas |  9 | 53.6
Atípicos con IQR, y las 43 líneas a precio cero · 18 min
SELECT COUNT(*) AS lineas,
       ROUND(SUM(cantidad * costo_unitario)) AS costo_entregado_clp
FROM ventas
WHERE precio_unitario = 0 AND moneda = 'CLP';
-- 42 | 56.234.143
Atípicos con IQR, y las 43 líneas a precio cero · 18 min
«43 líneas a precio cero, repartidas en las cuatro líneas de negocio. No están concentradas en un producto ni en un cliente ni en un mes: un error de digitación se concentra; un proceso de negocio se reparte. Y salieron de bodega 56,2 millones de pesos a costo que entraron como cero pesos de venta.»

Y la palabra que hay que ponerle, porque el corrector la busca: código centinela.

Atípicos con IQR, y las 43 líneas a precio cero · 18 min
«Un centinela es un valor imposible que el sistema usa para decir «no sé»: 0 en un precio, 9999 en un peso, 99 en una edad, 1900-01-01 en una fecha. No es un error de digitación ni un faltante declarado: es un NULL disfrazado de número, y por eso pasa por todos los controles y entra a los promedios como si fuera un dato.

Y se detecta con una sola pregunta: ¿qué valores NO puede tomar esta columna? Donde aparece lo imposible, ahí está el centinela.»
Atípicos con IQR, y las 43 líneas a precio cero · 18 min

Hilo 3 — salir de Excel: «En Excel esto sale como #¡DIV/0!, y lo que hace todo el mundo es envolverlo en un SI.ERROR(...; 0) para que la planilla se vea limpia. Ese SI.ERROR es el problema entero del curso en una función: convierte 43 preguntas de negocio sin responder en 43 ceros que se suman al promedio.»

Respiro · 5 min
La bisagra · 4 min

Éste es el bloque que convierte dos sesiones en una clase. Se dicta de pie, sin proyectar SQL.

«El precio 0 y la cantidad negativa parecen el mismo tipo de basura. No lo son.»

Y la pregunta colgada, cerrada acá con ellos:

La bisagra · 4 min
«Nos preguntamos si los 639 eran error o plata en la calle. Ya está: eran plata en la calle, y lo supimos mirando el patrón, no la celda. Ahora tenemos dos casos más sobre la mesa, y la sala ya los está tratando igual: 43 líneas a precio cero y 109 con cantidad negativa. Las dos se ven exactamente igual de sucias en la tabla.

Una de las dos es ambigua y hay que preguntar. La otra es información contabilizada, con documento tributario detrás, y filtrarla te va a mover 219 millones de venta. En los próximos veinte minutos las separamos.»
Notas de crédito: 109 líneas que no son basura · 18 min
SELECT COUNT(*) AS lineas_negativas,
       COUNT(DISTINCT numero_factura) AS facturas,
       ROUND(SUM(cantidad * precio_unitario)) AS venta_devuelta_clp
FROM ventas
WHERE cantidad < 0;
-- 109 | 54 | -218.962.202
Notas de crédito: 109 líneas que no son basura · 18 min
«109 líneas en 54 facturas. 219 millones de pesos en negativo. Y ahora la pregunta que ordena la clase: ¿es basura o es información?»

Dejar que respondan. Alguien va a decir "hay que filtrarlas para que no ensucien". Perfecto: hacerlo en vivo.

Notas de crédito: 109 líneas que no son basura · 18 min
WITH factura AS (
  SELECT numero_factura,
         SUM(cantidad * precio_unitario) AS bruto,
         SUM(cantidad * costo_unitario)  AS costo,
         ANY_VALUE(descuento_factura)    AS descuento,
         ANY_VALUE(flete_despacho)       AS flete,
         MIN(cantidad)                   AS min_cantidad
  FROM ventas GROUP BY numero_factura
)
SELECT 'con notas de crédito' AS escenario,
       ROUND(100.0 * (SUM(bruto) - SUM(costo) - SUM(descuento) - SUM(flete)) / SUM(bruto), 2) AS margen_pct,
       ROUND(SUM(bruto) / 1e6, 1) AS venta_MM
FROM factura
UNION ALL
SELECT 'sin notas de crédito (filtradas)',
       ROUND(100.0 * (SUM(bruto) - SUM(costo) - SUM(descuento) - SUM(flete)) / SUM(bruto), 2),
       ROUND(SUM(bruto) / 1e6, 1)
FROM factura WHERE min_cantidad >= 0;
-- con notas de crédito             | 24.59 | 9129.8
-- sin notas de crédito (filtradas) | 24.63 | 9348.8
Notas de crédito: 109 líneas que no son basura · 18 min

Y aquí hay que ser honesto, porque es más interesante que el titular fácil:

Notas de crédito: 109 líneas que no son basura · 18 min
«Miren el margen: 24,59 % contra 24,63 %. Casi no se mueve. Cuatro centésimas.

Ahora miren la venta: 9.129,8 contra 9.348,8 millones. Filtrar las 109 líneas le suma 219 millones a la venta que informas. Un 2,34 % de venta que el cliente ya devolvió y que la empresa ya no tiene.

Ése es el punto fino: el ratio apenas se mueve, el nivel se mueve mucho. Si el bono comercial se paga sobre venta bruta, acabas de repartir bonos por ventas devueltas. Si la meta del año se mide sobre venta, acabas de cumplirla con mercadería que volvió a bodega.»
Notas de crédito: 109 líneas que no son basura · 18 min

Y dónde se concentran, porque el patrón también informa:

Notas de crédito: 109 líneas que no son basura · 18 min
SELECT upper(strip_accents(trim(segmento))) AS segmento,
       COUNT(*) FILTER (WHERE cantidad < 0) AS lineas_nc,
       ROUND(-SUM(CASE WHEN cantidad < 0 THEN cantidad * precio_unitario ELSE 0 END) / 1e6, 1) AS devuelto_MM
FROM ventas GROUP BY 1 ORDER BY devuelto_MM DESC;
-- CONSTRUCCION | 33 | 106.7
-- RETAIL       | 24 |  45.6
-- INDUSTRIAL   | 29 |  30.5
-- PUBLICO      | 16 |  27.8
-- MINERIA      |  7 |   8.5
Notas de crédito: 109 líneas que no son basura · 18 min
«Construcción devuelve 106,7 millones, casi la mitad del total, con 33 líneas. Devoluciones grandes y pocas: eso tiene forma de material rechazado en obra, no de error de digitación. Y es una pregunta comercial, no de datos.»

La frase que hay que dejar clavada:

Notas de crédito: 109 líneas que no son basura · 18 min
Una empresa distribuidora sin devoluciones sería el dato sospechoso. El cero es lo raro. Lo que se hace con las notas de crédito no es borrarlas: es analizar en neto y declarar el criterio.

Y la matriz, que es el corazón del requisito 4 del Parcial 1. Se copia entera —últimos 4 minutos del bloque:

Notas de crédito: 109 líneas que no son basura · 18 min
SeñalQué esEjemplos de hoyTratamiento
Error de sistema o capturael dato no debería existir asítipo de cambio vacío en 89 líneas · fecha dd/mm en 21 líneas · una fecha del año 2035corregir y documentar la corrección
Información legítima del negocioel dato es raro porque el negocio lo es109 notas de crédito · 389 líneas atípicas de venta de proyecto · 639 de cartera abiertaconservar, clasificar y contar aparte
Ambiguono se puede decidir sin preguntar43 líneas a precio 0 · el cliente duplicado del maestroregla declarada + riesgo residual escrito
Notas de crédito: 109 líneas que no son basura · 18 min
«La tercera fila es la que separa un 4 de un 7 en la rúbrica. No se evalúa que aciertes: se evalúa que declares. Un supuesto explícito suma; un supuesto escondido resta.»

Hilo 2: «Esta discusión tiene fecha fija: el cierre mensual. Comercial informa la venta bruta porque así se ve la meta, y Contabilidad informa la venta neta porque así lo exige el libro de compras y ventas. Los dos tienen razón y los dos salen del mismo archivo.»

Normalización de texto: la cascada completa, hasta donde llega · 18 min

Volvemos a los 100 nombres, ahora con el método completo y medido:

Normalización de texto: la cascada completa, hasta donde llega · 18 min
SELECT COUNT(DISTINCT cliente) AS crudo,
       COUNT(DISTINCT upper(trim(cliente))) AS mas_caja_y_bordes,
       COUNT(DISTINCT upper(regexp_replace(trim(cliente), ' +', ' ', 'g'))) AS mas_espacios_internos,
       COUNT(DISTINCT upper(strip_accents(
             rtrim(regexp_replace(trim(cliente), ' +', ' ', 'g'), '.')))) AS mas_punto_final,
       COUNT(DISTINCT upper(replace(replace(replace(rut_cliente,'.',''),'-',''),' ',''))) AS por_rut_normalizado
FROM ventas;
-- 100 | 64 | 46 | 24 | 18
Normalización de texto: la cascada completa, hasta donde llega · 18 min

La cascada, escrita en la pizarra como escalera: 100 → 64 → 46 → 24 → 18.

Normalización de texto: la cascada completa, hasta donde llega · 18 min
«Cada escalón es una operación y una apuesta. Poner todo en mayúsculas es segura. Colapsar espacios, segura. Quitar el punto final, casi segura. Y cuando llegas a 24 todavía te faltan seis, y las seis exigen decidir si SA y S.A. son la misma sociedad. En este archivo lo son. En un archivo con dos mil clientes, alguna vez no lo van a ser — y ahí tu limpieza fusiona dos empresas distintas y nadie se entera nunca.

Normalizar caja y espacios reduce las formas y no las cierra: sin el RUT no se cierra. El RUT normalizado hace el trayecto completo en una sola operación y sin apostar: 74 → 18.»
Normalización de texto: la cascada completa, hasta donde llega · 18 min

Regla del oficio, se copia:

Normaliza el texto para mostrar. Agrupa por la llave para contar. Y cuando no hay llave, cada paso de limpieza va escrito en el informe, porque es una decisión, no una obviedad.

Y los otros dos campos, para cerrar el inventario de suciedad del caso propio:

Normalización de texto: la cascada completa, hasta donde llega · 18 min
SELECT COUNT(DISTINCT segmento)       AS formas_segmento,
       COUNT(DISTINCT upper(strip_accents(trim(segmento))))       AS segmentos_reales,
       COUNT(DISTINCT region_cliente) AS formas_region,
       COUNT(DISTINCT upper(strip_accents(trim(region_cliente)))) AS regiones_reales
FROM ventas;
-- 23 | 5 | 62 | 14
Normalización de texto: la cascada completa, hasta donde llega · 18 min
«100 formas para 18 clientes · 74 formas para 18 RUT · 23 segmentos para 5 · 62 regiones para 14. Ése es el inventario completo de suciedad de texto de este archivo, medido. Los cuatro números van al informe de calidad, cada uno con su consulta.»
El archivo oficial del Parcial 1: misma lección, otro país · 10 min

Anunciarlo sin drama, mirando a la sala:

«Este archivo es el del parcial. Hoy le damos el primer vistazo entre todos. Ese día lo hacen ustedes solos, con la rúbrica. No hay sorpresa y no la va a haber: la sorpresa es mala pedagogía.»
El archivo oficial del Parcial 1: misma lección, otro país · 10 min
CREATE OR REPLACE TABLE fac AS SELECT * FROM read_csv_auto('../MATERIAL/ventas_por_factura.csv');

SELECT COUNT(*) AS filas,
       COUNT(DISTINCT "N° de factura") AS folios,
       COUNT(DISTINCT "ID Cliente")    AS clientes
FROM fac;
-- 25953 | 25900 | 4372
El archivo oficial del Parcial 1: misma lección, otro país · 10 min

Las devoluciones, aquí, vienen marcadas en el folio con una C:

El archivo oficial del Parcial 1: misma lección, otro país · 10 min
SELECT COUNT(*) AS filas,
       COUNT(*) FILTER (WHERE "N° de factura" LIKE 'C%') AS filas_C,
       ROUND(100.0 * COUNT(*) FILTER (WHERE "N° de factura" LIKE 'C%') / COUNT(*), 2) AS pct_C,
       COUNT(*) FILTER (WHERE "ID Cliente" IS NULL) AS sin_id_cliente,
       ROUND(100.0 * COUNT(*) FILTER (WHERE "ID Cliente" IS NULL) / COUNT(*), 2) AS pct_sin_id
FROM fac;
-- 25953 | 3841 | 14.8 | 3724 | 14.35
El archivo oficial del Parcial 1: misma lección, otro país · 10 min
SELECT ROUND(SUM(Monto)) AS neto,
       ROUND(SUM(Monto) FILTER (WHERE "N° de factura" NOT LIKE 'C%')) AS solo_ventas,
       ROUND(SUM(Monto) FILTER (WHERE "N° de factura" LIKE 'C%'))     AS devoluciones
FROM fac;
-- 9.749.440 | 10.646.332 | -896.892
El archivo oficial del Parcial 1: misma lección, otro país · 10 min
«La misma lección, otro país, otro idioma, otra moneda. Un retailer británico, 26 mil filas, un 14,8 % de documentos de devolución y casi 897 mil de devoluciones sobre 10,6 millones brutos. Y ustedes ya saben qué hacer: analizar en neto y declararlo. No aprendieron el caso de Austral: aprendieron el método.»

Y la trampa fina, en una sola consulta —si el reloj llegó acá a las 22:05, se proyecta y se lee; si no, va al simulacro:

El archivo oficial del Parcial 1: misma lección, otro país · 10 min
SELECT COUNT(*) FILTER (WHERE Cantidad < 0) AS cantidad_negativa,
       COUNT(*) FILTER (WHERE Cantidad < 0 AND "N° de factura" LIKE 'C%')     AS negativa_con_folio_C,
       COUNT(*) FILTER (WHERE Cantidad < 0 AND "N° de factura" NOT LIKE 'C%') AS negativa_sin_folio_C,
       COUNT(*) FILTER (WHERE Monto = 0) AS monto_cero
FROM fac;
-- 5179 | 3841 | 1338 | 2105
El archivo oficial del Parcial 1: misma lección, otro país · 10 min

Silencio. «5.179 cantidades negativas. Sólo 3.841 tienen folio de devolución. Las otras 1.338 tienen cantidad negativa, monto cero y ningún cliente, las tres cosas a la vez. No son ventas y no son devoluciones a un cliente: son ajustes de inventario. Es una tercera población dentro de la misma tabla, y ninguna herramienta te la señala: la encontraste porque contaste dos veces y los números no calzaron. Ésa es la habilidad: no la consulta, la desconfianza.»

Control quincenal C2 · 10 min
Experto de negocio interno, síntesis y ticket · 11 min

Los dos roles en la misma lámina. Las dudas concretas del dato de hoy, escritas en la pizarra:

Gerencia Comercial: «43 líneas salieron a precio cero, por 56,2 millones a costo. ¿Es un error de digitación, o es una muestra comercial y una reposición de garantía?»

Contador / Cuentas por Cobrar: «¿Esta cantidad negativa es un error de digitación o es una nota de crédito emitida?»
Experto de negocio interno, síntesis y ticket · 11 min
«Las dos cosas son plausibles en el precio cero y el archivo no lo puede decir. La evidencia que sí tenemos: están repartidas en las cuatro líneas de negocio y en los tres años. Eso empuja hacia "proceso" y no hacia "error de dedo", pero es una inferencia, no una respuesta. Quien la tiene es Gerencia Comercial: ella sabe si la empresa entrega muestras, con qué autorización y contra qué cuenta contable. Y la respuesta cambia el tratamiento por completo: si es muestra, es gasto comercial y se excluye del cálculo de margen; si es error, hay que corregir el precio y rehacer el margen del período.»

«Y con la cantidad negativa, lo mismo por el otro lado: las dos cosas se ven exactamente igual en el archivo. Un −17 puede ser una devolución contabilizada o un dedo que se resbaló. La diferencia está en si existe el documento tributario que la respalda. Quien lo sabe es el Contador o Cuentas por Cobrar: ellos tienen el libro de compras y ventas, y ahí una nota de crédito tiene folio propio. Si tiene folio, es información. Si no lo tiene, es un error que además descuadra el IVA, y eso es un problema mayor que tu informe.»
Experto de negocio interno, síntesis y ticket · 11 min
Duda que salió del datoEl rol que tiene la respuesta
¿El precio 0 es error, muestra o reposición de garantía?Gerencia Comercial
¿La cantidad negativa es error o nota de crédito?Contador / Cuentas por Cobrar
¿Las 639 sin fecha de pago están impagas o falta cargar el pago?Cuentas por Cobrar
¿Las 389 líneas atípicas son ventas de proyecto o pedidos mal digitados?Jefe de Administración de Ventas (y el KAM de la cuenta)
¿La venta con que se pagan las comisiones es bruta o neta de devoluciones?Control de Gestión (y esa respuesta cambia el bono de alguien)
Experto de negocio interno, síntesis y ticket · 11 min

Y la frase que ordena el informe que van a escribir en la clase 06:

«Un informe de calidad que dice "hay 43 líneas a precio cero" está a la mitad. El informe completo dice: 43 líneas · aquí está la consulta · le pregunté a Gerencia Comercial · dijo esto · por eso las traté así · y esto queda sin resolver.»

Síntesis, construida con ellos:

Experto de negocio interno, síntesis y ticket · 11 min
  1. «¿Cuáles son los tres tipos de faltante?» → por diseño, por omisión, por tercero.
  2. «¿Qué es un atípico?» → un valor fuera de un criterio declarado, no un valor que a ti te parece raro. Y las 257 sierras no se borran: se marcan y se cuentan aparte.
  3. «Filtrar las notas de crédito, ¿qué mueve más: el margen o la venta?» → la venta: 219 millones, un 2,34 %.
  4. «¿Hasta dónde llega limpiar el texto?» → 100 → 46 sin apostar; el resto sale del RUT.
Experto de negocio interno, síntesis y ticket · 11 min

Ticket TC05 (3 min, se proyecta, después del C2): a) La regla que separa un error de captura de un dato del negocio, en una frase. b) 43 líneas con precio_unitario = 0 y 109 con cantidad negativa en 54 facturas: di qué haces con cada grupo antes de calcular el margen, y a qué rol le preguntas por cada uno. c) 1–5 y qué te falta.

Lectura de Griffiths asignada con guía escrita (capítulos de estadística descriptiva: media, mediana, cuartiles, dispersión). La consigna es una sola pregunta: «¿en qué caso el promedio es la medida correcta y en cuál no?» Se responde en la clase 13 con estos mismos datos.

Experto de negocio interno, síntesis y ticket · 11 min

Pregunta que queda planteada (se escribe en la pizarra y no se responde hoy):

→ Ya sabes qué está sucio y por qué. ¿Cómo se lo cuentas a alguien que no va a leer una sola consulta?

Puente a la clase 06:

Experto de negocio interno, síntesis y ticket · 11 min
«La próxima se escribe. No se consulta: se escribe. Porque el trabajo no termina cuando encontraste el problema — termina cuando alguien con poder de decidir lo entendió, lo autorizó y firmó el riesgo que queda. Y esa persona tiene ocho minutos y no sabe SQL.»
Clase 05 · 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-05.ipynb

← → avanzar · P proyector · F pantalla completa
GAA1104 · C05 · Calidad completa: qué está roto y qué está vivo (+ Control C2) 20:30 1 / 1