← Volver al índice de anexos
Macrobloque 2·Datos·Anexo 11 / 40

Anexo 11 · Staging y normalización

Etapa: Fases 3.1 y 3.2
NDA RECOMENDADO

ANEXO 11

Staging y normalización de datos

Este anexo corresponde a la Fase 3 — Preparación, especialmente a las etapas “Staging” y “Normalización” de FARO Connect.


1. Objetivo del anexo

El objetivo del Anexo 11 — Staging y normalización es explicar cómo FARO Connect transforma datos crudos, sucios o inconsistentes en datos limpios, comparables y listos para ser usados por KPIs, reglas, alertas, tensiones, diagnósticos, acciones y FARO Score.

La pregunta central es:

¿Cómo convierte FARO datos desordenados en información utilizable para dirigir?

Ejemplo simple:

RAW:
"Cem x50", "27/05/26", "$ 8.500", "Juan P.", "SJ"

Staging:
producto = "cem x50"
fecha = "2026-05-27"
precio = 8500
vendedor = "juan p"
sucursal = "sj"

Normalización:
producto_id = PROD_001 / CEMENTO_BOLSA_50KG
vendedor_id = EMP_014 / Juan Pérez
sucursal_id = SUC_SAN_JUAN

2. Tesis del Anexo 11

La tesis es:

FARO no puede interpretar una empresa si primero no logra que sus datos hablen el mismo idioma.

En la práctica, los datos empresariales vienen escritos de muchas formas:

Cem 50
Cemento x50
Cem. x 50kg
Bolsa cemento
CEMENTO 50KG

Para una persona puede ser obvio. Para un sistema no.

FARO debe transformar todas esas variantes en una entidad única:

CEMENTO_BOLSA_50KG

Sin staging y normalización, los KPIs salen torcidos, las alertas se duplican, las tensiones se detectan mal y el FARO Score pierde confianza.


3. Diferencia entre Staging y Normalización

Capa Qué hace Ejemplo
RAW Guarda el dato original tal como llegó. “$ 8.500”, “Cem x50”, “27/05/26”.
Staging Limpia formato técnico. 8500, “cem x50”, “2026-05-27”.
Normalización Unifica contra reglas y maestros. PROD_001, CEMENTO_BOLSA_50KG.
Modelo ejecutivo Usa el dato para análisis. Venta con producto, cliente, margen, vendedor y sucursal.

En criollo:

RAW = lo que llegó.
Staging = lo limpio.
Normalización = lo entendido.
Modelo ejecutivo = lo usable para dirigir.

4. Qué es Staging

Staging es una zona intermedia donde los datos se limpian técnicamente antes de integrarse al modelo ejecutivo.

No toma decisiones. No interpreta negocio profundo. Primero ordena.

Staging corrige:

Fechas.
Monedas.
Decimales.
Mayúsculas y minúsculas.
Espacios.
Caracteres raros.
Separadores.
Duplicados evidentes.
Campos vacíos.
Tipos de datos.
Columnas mal nombradas.
Formatos regionales.

Ejemplo:

"$ 1.250.000,50" → 1250000.50
"  Juan P. " → "juan p"
"27/5/26" → "2026-05-27"
"8%" → 0.08

5. Qué es Normalización

Normalización es el proceso por el cual FARO convierte datos limpios pero todavía ambiguos en datos estandarizados, vinculados a una entidad oficial.

Ejemplo:

"Juan P."
"J. Pérez"
"Juan Perez"
"JPerez"

Todos deben vincularse a:

EMP_014 — Juan Pérez

La normalización conecta datos con:

Clientes.
Productos.
Empleados.
Proveedores.
Sucursales.
Cuentas.
Áreas.
Rubros.
Centros de costo.
Canales.
Zonas.
Procesos.

6. Por qué esta etapa es crítica

Si no hay staging / normalización Consecuencia
Productos escritos distinto Stock, margen y ventas por producto quedan mal.
Clientes duplicados Mora, rentabilidad y riesgo por cliente quedan distorsionados.
Vendedores mal identificados Comisiones y desempeño salen incorrectos.
Fechas inconsistentes Comparaciones mensuales o semanales fallan.
Monedas mal convertidas Caja, ventas y gastos quedan irreales.
Gastos mal clasificados Dirección no sabe dónde se va la plata.
Sucursales no normalizadas No se puede comparar unidades.
Proveedores duplicados No se detecta dependencia ni cumplimiento real.

La normalización es poco vistosa, pero es donde se gana o se pierde la credibilidad del sistema. Es la cocina; nadie la ve en el salón, pero si falla, se intoxican todos.


7. Flujo completo de preparación

RAW
→ Validación inicial
→ Staging
→ Limpieza técnica
→ Estandarización de formatos
→ Normalización contra diccionarios
→ Match contra tablas maestras
→ Resolución de alias
→ Clasificación FARO
→ Enriquecimiento
→ Modelo ejecutivo

8. Reglas de limpieza en Staging

La biblioteca inicial de reglas de staging puede tener:

30 a 80 reglas base

Escalable a:

200+ reglas por fuente, industria, país, moneda y módulo.

Ejemplos de reglas

Código Regla Ejemplo
STG-001 Convertir fecha a formato ISO. 27/05/262026-05-27
STG-002 Convertir moneda a número. $ 8.500,508500.50
STG-003 Limpiar espacios. " Juan ""Juan"
STG-004 Pasar texto a minúsculas para match. "CEMENTO""cemento"
STG-005 Remover caracteres especiales innecesarios. "Cem. x 50kg""cem x 50kg"
STG-006 Convertir porcentaje. "8%"0.08
STG-007 Detectar importes negativos. -5000 → observar
STG-008 Detectar registros vacíos. fila sin datos → rechazar
STG-009 Normalizar booleanos. "sí", "SI", "true"true
STG-010 Convertir cantidades a número. "100 bolsas"100

9. Código ejemplo: limpieza de fecha

from datetime import datetime

def normalizar_fecha(valor):
    formatos = ["%d/%m/%y", "%d/%m/%Y", "%Y-%m-%d"]

    for formato in formatos:
        try:
            return datetime.strptime(valor, formato).date().isoformat()
        except ValueError:
            continue

    return None

Ejemplo:

normalizar_fecha("27/05/26")

Resultado:

2026-05-27

10. Código ejemplo: limpieza de moneda argentina

def normalizar_moneda(valor):
    if valor is None:
        return None

    texto = str(valor)
    texto = texto.replace("$", "")
    texto = texto.replace(" ", "")
    texto = texto.replace(".", "")
    texto = texto.replace(",", ".")

    try:
        return float(texto)
    except ValueError:
        return None

Ejemplo:

normalizar_moneda("$ 1.250.000,50")

Resultado:

1250000.50

11. Código ejemplo: normalización de porcentaje

def normalizar_porcentaje(valor):
    if valor is None:
        return None

    texto = str(valor).replace("%", "").replace(",", ".").strip()

    try:
        numero = float(texto)
        return numero / 100 if numero > 1 else numero
    except ValueError:
        return None

Ejemplo:

normalizar_porcentaje("8%")

Resultado:

0.08

12. Código ejemplo: limpieza general de texto

import unicodedata
import re

def limpiar_texto(valor):
    if valor is None:
        return None

    texto = str(valor).strip().lower()

    texto = unicodedata.normalize("NFKD", texto)
    texto = "".join(c for c in texto if not unicodedata.combining(c))

    texto = re.sub(r"[^a-z0-9\s]", " ", texto)
    texto = re.sub(r"\s+", " ", texto)

    return texto.strip()

Ejemplo:

limpiar_texto("  Cem. x 50KG  ")

Resultado:

cem x 50kg

13. Staging por módulo

13.1 Comercial

Dato Limpieza necesaria
Fecha venta Convertir a fecha estándar.
Cliente Limpiar texto y preparar para match.
Producto Limpiar alias y unidades.
Precio Convertir a número.
Descuento Convertir a porcentaje decimal.
Vendedor Limpiar nombre y vincular empleado.
Sucursal Normalizar código o nombre.
Canal Estandarizar: mostrador, obra, online, mayorista.

13.2 Finanzas

Dato Limpieza necesaria
Fecha cobro Formato estándar.
Monto Número positivo o negativo según tipo.
Cuenta bancaria Código normalizado.
Cliente / proveedor Match contra maestros.
Tipo movimiento cobro, pago, transferencia, ajuste.
Centro de costo Clasificación FARO.
Comprobante Normalizar número.

13.3 Stock

Dato Limpieza necesaria
Producto Normalizar alias.
Código Limpiar formato.
Stock actual Número.
Stock mínimo Número.
Ubicación Sucursal / depósito.
Movimiento ingreso, egreso, ajuste.
Fecha movimiento Fecha estándar.
Proveedor Match contra maestro.

13.4 RRHH

Dato Limpieza necesaria
Empleado Normalizar nombre.
Área Vincular a área FARO.
Rol Estandarizar cargo.
Sueldo Convertir a número.
Comisión Convertir a número o porcentaje.
Ausentismo Fecha, horas, motivo.
Superior Vincular responsable.

13.5 Workflow / Dirección

Dato Limpieza necesaria
Acción Texto limpio.
Responsable Match contra usuarios / empleados.
Vencimiento Fecha estándar.
Estado pendiente, en proceso, bloqueada, vencida, cerrada.
Prioridad baja, media, alta, crítica.
KPI relacionado Match contra biblioteca de KPIs.
Tensión relacionada Match contra biblioteca de tensiones.

14. Diccionario FARO de equivalencias

La normalización usa diccionarios.

Ejemplo de equivalencias de producto:

Alias detectado Producto normalizado product_id
Cem x50 CEMENTO_BOLSA_50KG PROD_001
Cemento 50 CEMENTO_BOLSA_50KG PROD_001
Bolsa cemento CEMENTO_BOLSA_50KG PROD_001
Cemento marca X 50 CEMENTO_BOLSA_50KG PROD_001
Cem. 50kg CEMENTO_BOLSA_50KG PROD_001

Ejemplo de equivalencias de sucursal:

Alias Sucursal normalizada branch_id
SJ SAN_JUAN SUC_SAN_JUAN
San Juan SAN_JUAN SUC_SAN_JUAN
S. Juan SAN_JUAN SUC_SAN_JUAN

15. Código ejemplo: match por diccionario

diccionario_productos = {
    "cem x50": "PROD_001",
    "cemento 50": "PROD_001",
    "bolsa cemento": "PROD_001",
    "cem 50kg": "PROD_001",
    "hierro 8": "PROD_020"
}

def normalizar_producto(nombre_producto):
    limpio = limpiar_texto(nombre_producto)
    return diccionario_productos.get(limpio)

Ejemplo:

normalizar_producto("Cem. x 50KG")

Resultado esperado:

PROD_001

16. Fuzzy matching para datos imperfectos

A veces el alias no coincide exactamente. FARO puede usar coincidencia aproximada.

Ejemplo:

from difflib import get_close_matches

def fuzzy_match(valor, opciones, umbral=0.80):
    valor_limpio = limpiar_texto(valor)
    opciones_limpias = [limpiar_texto(o) for o in opciones]

    coincidencias = get_close_matches(
        valor_limpio,
        opciones_limpias,
        n=1,
        cutoff=umbral
    )

    if coincidencias:
        return coincidencias[0]

    return None

Uso:

"Cemnto 50kg" podría sugerirse como "cemento 50kg"

Regla importante:

El fuzzy matching puede sugerir, pero los cambios críticos deben validarse si la confianza es baja.


17. Score de confianza de normalización

No todos los matches tienen la misma confianza.

Tipo de match Confianza
Match exacto por ID 1.00
Match exacto por alias validado 0.95
Match aproximado alto 0.80 - 0.90
Match aproximado medio 0.60 - 0.79
Sin match 0.00

Ejemplo:

def clasificar_confianza_match(tipo_match, score=None):
    if tipo_match == "id_exacto":
        return 1.0
    if tipo_match == "alias_validado":
        return 0.95
    if tipo_match == "fuzzy" and score:
        return score
    return 0.0

Uso ejecutivo:

Producto normalizado con confianza 0.95 → puede alimentar KPIs.
Producto normalizado con confianza 0.62 → requiere revisión antes de decisiones críticas.

18. Tabla de alias pendientes

FARO debe tener una bandeja de revisión para alias no reconocidos.

Alias detectado Fuente Veces encontrado Sugerencia Confianza Acción
Cemnto 50 Excel ventas 38 CEMENTO_BOLSA_50KG 0.82 Aprobar
H° 8mm Compras 12 HIERRO_8MM 0.76 Revisar
Juan Perz Ventas 5 Juan Pérez 0.80 Aprobar
Obra Nte CRM 9 Obra Norte 0.71 Revisar

19. Normalización contra tablas maestras

La normalización debe conectar cada valor con una tabla maestra.

Entidad Maestro destino
Producto dim_product
Cliente dim_customer
Empleado dim_employee
Proveedor dim_supplier
Sucursal dim_branch
Cuenta dim_account
Área dim_area
Rubro dim_category
Canal dim_channel
Zona dim_zone

Ejemplo SQL:

SELECT
    s.sale_id,
    p.product_id,
    c.customer_id,
    e.employee_id,
    b.branch_id
FROM staging_sales s
LEFT JOIN dim_product p
    ON s.product_alias = p.product_alias
LEFT JOIN dim_customer c
    ON s.customer_alias = c.customer_alias
LEFT JOIN dim_employee e
    ON s.seller_alias = e.employee_alias
LEFT JOIN dim_branch b
    ON s.branch_alias = b.branch_alias;

20. Diseño de tablas staging

20.1 Staging de ventas

CREATE TABLE staging_sales (
    id UUID PRIMARY KEY,
    load_id TEXT NOT NULL,
    raw_id UUID,
    sale_date DATE,
    customer_raw TEXT,
    customer_clean TEXT,
    product_raw TEXT,
    product_clean TEXT,
    seller_raw TEXT,
    seller_clean TEXT,
    branch_raw TEXT,
    branch_clean TEXT,
    quantity NUMERIC,
    unit_price NUMERIC,
    discount_rate NUMERIC,
    total_amount NUMERIC,
    status TEXT,
    created_at TIMESTAMP DEFAULT now()
);

20.2 Staging de stock

CREATE TABLE staging_stock (
    id UUID PRIMARY KEY,
    load_id TEXT NOT NULL,
    raw_id UUID,
    product_raw TEXT,
    product_clean TEXT,
    branch_raw TEXT,
    branch_clean TEXT,
    stock_current NUMERIC,
    stock_minimum NUMERIC,
    location_raw TEXT,
    movement_date DATE,
    status TEXT,
    created_at TIMESTAMP DEFAULT now()
);

20.3 Staging financiero

CREATE TABLE staging_finance_movements (
    id UUID PRIMARY KEY,
    load_id TEXT NOT NULL,
    raw_id UUID,
    movement_date DATE,
    description_raw TEXT,
    description_clean TEXT,
    amount NUMERIC,
    movement_type TEXT,
    account_raw TEXT,
    account_clean TEXT,
    customer_raw TEXT,
    supplier_raw TEXT,
    cost_center_raw TEXT,
    status TEXT,
    created_at TIMESTAMP DEFAULT now()
);

21. Normalización de productos

La normalización de productos debe contemplar:

Código interno.
Nombre comercial.
Marca.
Presentación.
Unidad.
Categoría.
Subcategoría.
Proveedor habitual.
Costo.
Precio lista.
Criticidad.
Rotación.

Ejemplo:

{
  "product_id": "PROD_001",
  "nombre_normalizado": "CEMENTO_BOLSA_50KG",
  "categoria": "Cemento",
  "unidad": "bolsa",
  "presentacion": "50kg",
  "proveedor_habitual": "PROV_010",
  "criticidad": "alta",
  "rotacion": "alta"
}

22. Normalización de clientes

Debe contemplar:

Razón social.
Nombre comercial.
CUIT / identificación fiscal.
Grupo económico.
Segmento.
Zona.
Canal.
Riesgo.
Condición de pago.
Historial de mora.
Rentabilidad.

Ejemplo:

{
  "customer_id": "CLI_003",
  "razon_social": "Constructora Norte SA",
  "nombre_comercial": "Obra Norte",
  "segmento": "constructoras",
  "zona": "san_juan",
  "condicion_pago": "30_dias",
  "riesgo": "medio",
  "rentabilidad_historica": "media"
}

23. Normalización de empleados

Debe contemplar:

Nombre completo.
Legajo.
Área.
Rol.
Sucursal.
Superior.
Estado.
Tipo de compensación.
Comisiones.
Responsabilidad RACI.

Ejemplo:

{
  "employee_id": "EMP_014",
  "nombre": "Juan Pérez",
  "area": "Comercial",
  "rol": "Vendedor",
  "sucursal": "SUC_SAN_JUAN",
  "superior": "EMP_002",
  "tipo_comision": "venta_y_margen"
}

24. Normalización de proveedores

Debe contemplar:

Razón social.
CUIT.
Rubro.
Productos asociados.
Plazo de entrega.
Condición de pago.
Nivel de cumplimiento.
Dependencia.
Riesgo.

Ejemplo:

{
  "supplier_id": "PROV_010",
  "razon_social": "Proveedor Norte SA",
  "rubro": "cemento",
  "plazo_entrega_dias": 7,
  "cumplimiento_historico": 0.82,
  "dependencia": "alta"
}

25. Normalización de gastos

Los gastos no deben quedar solamente como cuentas contables. FARO necesita lectura gerencial.

Ejemplo:

OSDE → Directorio
Flete → Logística
Comisión bancaria → Finanzas
Publicidad → Comercial / Marketing
Uniformes → RRHH / Operaciones
Reparación camión → Logística / Operaciones

Regla ejemplo:

def clasificar_gasto(descripcion):
    texto = limpiar_texto(descripcion)

    if "osde" in texto:
        return {"area": "Directorio", "categoria": "Salud directores"}

    if "flete" in texto or "transporte" in texto:
        return {"area": "Logística", "categoria": "Distribución"}

    if "publicidad" in texto or "meta ads" in texto:
        return {"area": "Comercial", "categoria": "Marketing"}

    return {"area": "Sin clasificar", "categoria": "Revisar"}

26. Resolución de duplicados

Clientes duplicados

Constructora Norte
Const. Norte
Constructora Norte SA
Obra Norte

Posible normalización:

CLI_003 — Constructora Norte SA

Productos duplicados

Cem x50
Cemento 50kg
Cemento bolsa

Posible normalización:

PROD_001 — CEMENTO_BOLSA_50KG

Empleados duplicados

Juan Pérez
Juan P.
J. Perez

Posible normalización:

EMP_014 — Juan Pérez

Código conceptual:

def detectar_posible_duplicado(valor, maestro, umbral=0.85):
    sugerencia = fuzzy_match(valor, maestro, umbral)
    if sugerencia:
        return {
            "valor": valor,
            "posible_match": sugerencia,
            "requiere_revision": True
        }
    return None

27. Reglas de bloqueo

No todos los datos pueden pasar al modelo ejecutivo.

Caso Acción
Venta sin fecha Rechazar.
Venta sin producto Rechazar.
Venta sin costo Procesar venta, bloquear margen.
Producto sin match Observar y enviar a revisión.
Cliente sin match Procesar parcialmente.
Stock negativo sin justificación Observar.
Acción sin responsable Bloquear workflow.
Tarea sin vencimiento Bloquear seguimiento.
Gasto sin área Enviar a clasificación.

28. Calidad después de staging y normalización

FARO debe recalcular calidad después de preparar datos.

Calidad RAW: 0.62
Calidad Staging: 0.78
Calidad Normalizada: 0.88

Ejemplo:

def mejora_calidad(score_raw, score_normalizado):
    return round(score_normalizado - score_raw, 2)

Lectura:

Si la calidad no mejora después del staging, el proceso de limpieza está mal diseñado.

29. Ejemplo completo: venta

RAW

{
  "fecha": "27/05/26",
  "cliente": "Obra Nte",
  "producto": "Cem x50",
  "cantidad": "100",
  "precio": "$ 8.500",
  "desc": "12%",
  "vend": "Juan P.",
  "suc": "SJ"
}

Staging

{
  "fecha": "2026-05-27",
  "cliente_clean": "obra nte",
  "producto_clean": "cem x50",
  "cantidad": 100,
  "precio_unitario": 8500,
  "descuento": 0.12,
  "vendedor_clean": "juan p",
  "sucursal_clean": "sj"
}

Normalización

{
  "customer_id": "CLI_003",
  "product_id": "PROD_001",
  "employee_id": "EMP_014",
  "branch_id": "SUC_SAN_JUAN",
  "fecha": "2026-05-27",
  "cantidad": 100,
  "precio_unitario": 8500,
  "descuento": 0.12
}

Modelo ejecutivo

{
  "venta_neta": 748000,
  "costo_total": 610000,
  "margen_bruto": 0.184,
  "vendedor": "Juan Pérez",
  "producto": "CEMENTO_BOLSA_50KG",
  "sucursal": "San Juan",
  "alerta_posible": "margen_critico_con_descuento_alto"
}

30. Ejemplo completo: gasto

RAW

{
  "fecha": "10/05/26",
  "descripcion": "OSDE Mayo",
  "monto": "$ 450.000",
  "cuenta": "gastos varios"
}

Staging

{
  "fecha": "2026-05-10",
  "descripcion_clean": "osde mayo",
  "monto": 450000,
  "cuenta_clean": "gastos varios"
}

Normalización FARO

{
  "area": "Directorio",
  "categoria": "Salud directores",
  "tipo_gasto": "gasto_directorio",
  "monto": 450000
}

Lectura ejecutiva

El gasto no debe imputarse a Administración general.
Debe clasificarse como gasto de Directorio.

31. Herramientas posibles

Necesidad Herramientas
Limpieza de datos Python, Pandas, SQL
Transformaciones dbt, SQL, Python
Orquestación Airflow, Prefect, Dagster, Celery
Almacenamiento staging PostgreSQL, BigQuery, Snowflake
Normalización Tablas de alias, reglas propias, fuzzy matching
Validación Great Expectations, dbt tests
Versionado de reglas Git, tablas de versiones, metadata
Procesamiento documentos Parsers PDF, OCR, extracción estructurada
Auditoría Logs, data lineage, checksums

32. Riesgos de mala normalización

Riesgo Consecuencia
Alias mal asignado Producto, cliente o empleado incorrecto.
Duplicados no resueltos KPIs inflados o fragmentados.
Normalización automática sin validación Errores masivos.
Falta de maestros No hay entidad oficial.
Reglas no versionadas No se puede saber cómo se procesó el dato.
Exceso de manualidad Proceso lento y dependiente de personas.
No medir confianza FARO actúa con seguridad falsa.

33. Output final del Anexo 11

Al finalizar este anexo, FARO debe tener definido:

1. Zona de staging por fuente.
2. Reglas de limpieza técnica.
3. Reglas de conversión de fechas, monedas, porcentajes y textos.
4. Diccionario de equivalencias.
5. Tablas de alias.
6. Proceso de normalización contra maestros.
7. Score de confianza de normalización.
8. Bandeja de alias pendientes.
9. Reglas de bloqueo.
10. Reglas de reprocesamiento.
11. Estructura de staging por módulo.
12. Campos limpios y campos normalizados.
13. Procedimiento para resolver duplicados.
14. Procedimiento para clasificar gastos, productos, clientes y responsables.
15. Datos listos para modelo ejecutivo.

34. Conexión con otros anexos

Próximo anexo Qué recibe desde Anexo 11
Anexo 8 — Fuentes e ingesta Datos recibidos desde fuentes.
Anexo 9 — RAW y trazabilidad Dato original y metadata.
Anexo 10 — Calidad de datos Validaciones y score inicial.
Anexo 12 — Clasificación FARO Datos limpios para clasificar por área, rubro y proceso.
Anexo 13 — Tablas maestras Entidades normalizadas y alias.
Anexo 14 — Modelo ejecutivo FARO Datos listos para análisis.
Anexo 17 — Biblioteca de KPIs Datos confiables para fórmulas.
Anexo 20 — Reglas de negocio Variables normalizadas para reglas.
Anexo 22 — Biblioteca de tensiones Variables comparables entre áreas.
Anexo 35 — FARO Score Base limpia para score confiable.

Staging y normalización son la etapa donde FARO convierte datos crudos en datos entendibles. Primero limpia formatos, fechas, monedas y textos; después unifica productos, clientes, empleados, proveedores, sucursales y cuentas contra diccionarios y tablas maestras. Sin esta etapa, los KPIs, alertas, tensiones y FARO Score pueden parecer correctos, pero estar construidos sobre datos mal interpretados.

Versión 1.0 · Última revisión: 2026-05-28 Anexo 11 de 40 · Fases 3.1 y 3.2