Target Encoding en Power BI: La Guía Definitiva Sin Data Leakage
Target Encoding en Power BI: 
La Guía Definitiva Sin Data Leakage
          Domina esta técnica esencial para modelos predictivos con validación cruzada, smoothing y prevención de overfitting. Código M paso a paso + mejores prácticas.
¿Qué es Target Encoding (Mean Encoding)?
Target Encoding es una técnica de codificación categórica que reemplaza cada categoría por el promedio de la variable objetivo para esa categoría. Es especialmente poderosa en modelos predictivos porque captura la relación real entre la categoría y el resultado.
Ejemplo Simple:
| Ciudad | Ventas | 
|---|---|
| Madrid | 1000 | 
| Barcelona | 800 | 
| Madrid | 1200 | 
| Valencia | 600 | 
Target Encoding:
| Ciudad | Target_Encoded | 
|---|---|
| Madrid | 1100 | 
| Barcelona | 800 | 
| Valencia | 600 | 
¿Cuándo Usar Target Encoding?
Alta Cardinalidad
>50 categorías únicas
ML Supervisado
Regresión o clasificación
Feature Engineering
AutoML, XGBoost, etc.
Riesgos Críticos: Data Leakage y Overfitting
Data Leakage: El Error Más Común
Si calculas el promedio usando toda la tabla y luego entrenas el modelo, el modelo ve información del futuro. ¡Overfitting garantizado!
Incorrecto (Data Leakage)
// ¡NO HAGAS ESTO!
PromedioGlobal = Table.Group(TodaLaTabla, {"Ciudad"}, {{"Avg", each List.Average([Ventas])}})
Correcto (Sin Leakage)
// Usa solo datos de entrenamiento
PromedioTrain = Table.Group(Entrenamiento, {"Ciudad"}, {{"Avg", each List.Average([Ventas])}})
Implementación Paso a Paso en Power Query
1 Prepara tus datos
Asegúrate de tener una columna categórica (ej. Ciudad) y una variable objetivo numérica (ej. Ventas).
2 Divide en Entrenamiento y Prueba
Usa Table.AddIndexColumn + Table.SelectRows para separar datos.
let
    Fuente = TuTabla,
    ConIndice = Table.AddIndexColumn(Fuente, "Índice", 0, 1),
    TotalFilas = Table.RowCount(ConIndice),
    Entrenamiento = Table.SelectRows(ConIndice, each [Índice] < TotalFilas * 0.8),
    Prueba = Table.SelectRows(ConIndice, each [Índice] >= TotalFilas * 0.8)
in
    [Entrenamiento, Prueba]
3 Calcula promedios en Entrenamiento
Promedios = Table.Group(Entrenamiento, {"Ciudad"}, {
    {"Target_Mean", each List.Average([Ventas]), type number},
    {"Conteo", each Table.RowCount(_), Int64.Type}
})
4 Une con todo el dataset
Resultado = Table.NestedJoin(Fuente, {"Ciudad"}, Promedios, {"Ciudad"}, "Encoding", JoinKind.LeftOuter),
Expandido = Table.ExpandTableColumn(Resultado, "Encoding", {"Target_Mean", "Conteo"}, {"Target_Encoded", "Cat_Count"})
Código M Completo (Listo para Copiar)
let
    // 1. Cargar datos
    Fuente = TuTablaOriginal,
    
    // 2. Agregar índice para división
    ConIndice = Table.AddIndexColumn(Fuente, "Índice", 0, 1, Int64.Type),
    TotalFilas = Table.RowCount(ConIndice),
    
    // 3. Dividir 80/20
    Entrenamiento = Table.SelectRows(ConIndice, each [Índice] < TotalFilas * 0.8),
    Prueba = Table.SelectRows(ConIndice, each [Índice] >= TotalFilas * 0.8),
    
    // 4. Calcular Target Encoding en entrenamiento
    EncodingTable = Table.Group(Entrenamiento, {"Ciudad"}, {
        {"Target_Mean", each List.Average([Ventas]), type nullable number},
        {"Cat_Count", each Table.RowCount(_), Int64.Type}
    }),
    
    // 5. Calcular promedio global (para smoothing)
    PromedioGlobal = List.Average(Entrenamiento[Ventas]),
    
    // 6. Aplicar smoothing (evita overfitting en categorías raras)
    MinSamples = 10,
    EncodingConSmoothing = Table.AddColumn(EncodingTable, "Target_Encoded", each 
        if [Cat_Count] < MinSamples then PromedioGlobal
        else ([Target_Mean] * [Cat_Count] + PromedioGlobal * MinSamples) / ([Cat_Count] + MinSamples)
    ),
    
    // 7. Unir con dataset completo
    Resultado = Table.NestedJoin(ConIndice, {"Ciudad"}, EncodingConSmoothing, {"Ciudad"}, "Temp", JoinKind.LeftOuter),
    Expandido = Table.ExpandTableColumn(Resultado, "Temp", {"Target_Encoded"}, {"Ciudad_Target"}),
    
    // 8. Limpiar
    Final = Table.SelectColumns(Expandido, List.RemoveItems(Table.ColumnNames(Expandido), {"Índice", "Temp"}))
in
    Final
Uso en DAX: Medidas Dinámicas
Ventas_Promedio_Ciudad = 
CALCULATE(
    AVERAGE(Ventas[Ventas]),
    ALLEXCEPT(Ciudades, Ciudades[Ciudad])
)
// Con filtro de fecha
Impacto_Temporal = 
CALCULATE(
    [Ventas_Promedio_Ciudad],
    DATESINPERIOD(Calendar[Date], MAX(Calendar[Date]), -30, DAY)
)
Conclusión: Tu Modelo Listo para Producción
Sin Data Leakage
Baja Dimensionalidad
Mejor Predicción
¡Ya dominas Target Encoding como un Data Scientist profesional! Implementa esta técnica en tus modelos de AutoML, exporta a Azure ML o intégrala en dashboards predictivos.