martes, 19 de octubre de 2021

Power Query: Diferencia dato previo condicionado

Este es sin duda un clásico de los cálculos: Obtener la diferencia con el dato previo, teniendo en cuenta un criterio temporal y una condición adicional (por ejemplo de país)
Power Query: Diferencia dato previo condicionado


Hace algún tiempo ya publiqué una forma de llegar a este dato (sin cumplir condición) simplemente siguiendo unos pasos a través del menú, empleando el truco de combinar la misma consulta sobre si misma...

En el caso de hoy añadimos una dificultad más, y es que las diferencias obtenidas deben respetar al conjunto de cada país, de tal forma que el primer dato de cada país no calcule diferencia sobre el último dato del país anterior... tal como se puede ver en la imagen anterior.

Así pues cargaremos nuestra tabla de datos al editor de Power Query como siempre, solo como conexión.
Y sin salir del editor crearemos una consulta en blanco donde escribiremos el siguiente código M:
let
    Origen = TblDATOS,
    //ordenamos la tabla por dos criterios: Primero por País y dentro de cada País por fecha
    FilasOrdenadas = Table.Sort(Origen,{{"País", Order.Ascending}, {"Fecha", Order.Ascending}}),
    //añadimos una columna con un índice comenzando en 0
    ÍndiceAgregado = Table.AddIndexColumn(FilasOrdenadas, "Índice", 0, 1, Int64.Type),

    //en este primer paso agregamos una columna donde aplica la diferencia 
    //de todas las filas respecto a la anterior... sin condiciones
    //nos apoyamos en la recién creada columna Índice
    AddCol_Delta1 = Table.AddColumn(ÍndiceAgregado, 
                        "Delta", 
                        each try [Importe]-FilasOrdenadas{[Índice]-1}[Importe] otherwise  null),

    //Agregamos una nueva columna que contenga una tabla con las filas filtradas de cada País
    //donde adicionalmente hemos incorporado un nuevo índice (independiente para cada País)
    //y sobre ese índice nuevo, calculamos la diferencia con el anterior dato
    AddCol_Delta2 = Table.AddColumn(AddCol_Delta1,
                        "Intermedio",
                        each
                        let
                            tblFiltroIndex=let 
                                p=[País],
                                TablaPAIS=Table.SelectRows(ÍndiceAgregado, each [País]=p),
                                AddIndice=Table.AddIndexColumn(TablaPAIS, "ÍndiceCondicion", 0, 1, Int64.Type)
                            in
                                Table.AddColumn(AddIndice,
                                   "DeltaSub",
                                   each try _[Importe]-AddIndice{[ÍndiceCondicion]-1}[Importe] otherwise null)
                        in
                            tblFiltroIndex  ),
    
    //finalmente recuperamos, en una nueva columna agregada, la diferencia obtenida en el paso anterior
    //solo cuando tengamos la coincidencia de Pais y Fecha...
    Coincidencia=Table.AddColumn(AddCol_Delta2, 
                        "Delta_Condicion",
                        each let 
                            p=[País], f=[Fecha], i=[Importe]
                            in 
                                Table.SelectRows([Intermedio], each [País]=p and [Fecha]=f and [Importe]=i)[DeltaSub]{0})
in
    Coincidencia

Power Query: Diferencia dato previo condicionado

Listo... al ejecutar la consulta obtenemos los datos esperados!!

El método empleado es una constante en Power Query, ir añadiendo columnas que faciliten el proceso o evolución del cálculo.
Relevante el uso de la expresión let...in...; sabiendo que la expresión let 'encapsula' un conjunto de valores que se van a calcular, a los que se van a asignar nombres (constantes o variables) que finalmente se van a usar en una expresión subsiguiente que sigue a la instrucción in.
Es decir, nos permite realizar cálculos intermedios dentro del proceso de creación de nuevas columnas...

Por ejemplo, el último paso de nuestra consulta:
Coincidencia=Table.AddColumn(AddCol_Delta2, 
                        "Delta_Condicion",
                        each let 
                            p=[País], f=[Fecha], i=[Importe]
                            in 
                                Table.SelectRows([Intermedio], each [País]=p and [Fecha]=f and [Importe]=i)[DeltaSub]{0})


Al mismo tiempo que agregamos una nueva columna 'Delta_Condición', procesamos un cálculo para tres variables:
p=[País], f=[Fecha], i=[Importe]
sobre las que se trabaja en la salida del in
donde realizamos una selección de filas con Table.SelectRows donde se cumplan las condiciones de igualdad definidas...

Un ejercicio interesante sin duda...

Un inconveniente del método descrito es que para un volumen alto de filas, el tiempo de ejecución es elevado :'(

No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.