Skip to content

Aggregations

Aggregations

Standard aggregations for batch KPI computation.

All aggregations operate column-wise on DataFrames and return a Series with one value per column.

Example:

>>> df = pd.DataFrame({'obj_1': [10, 20, 30], 'obj_2': [15, 25, 35]})
>>> Aggregations.Mean(df)
    pd.Series({'obj_1': 20.0, 'obj_2': 25.0})
Source code in submodules/mesqual/mesqual/kpis/aggregations.py
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
class Aggregations:
    """
    Standard aggregations for batch KPI computation.

    All aggregations operate column-wise on DataFrames and return
    a Series with one value per column.

    Example:

        >>> df = pd.DataFrame({'obj_1': [10, 20, 30], 'obj_2': [15, 25, 35]})
        >>> Aggregations.Mean(df)
            pd.Series({'obj_1': 20.0, 'obj_2': 25.0})
    """

    # Basic statistical aggregations
    Sum = Aggregation(
        'Sum',
        lambda df: _column_wise_sum(_ensure_frame_format(df))
    )
    Total = Aggregation(
        'Total',
        lambda df: _column_wise_sum(_ensure_frame_format(df))
    )
    Mean = Aggregation(
        'Mean',
        lambda df: _ensure_frame_format(df).mean(axis=0)
    )
    Max = Aggregation(
        'Max',
        lambda df: _ensure_frame_format(df).max(axis=0)
    )
    Min = Aggregation(
        'Min',
        lambda df: _ensure_frame_format(df).min(axis=0)
    )

    # Time-based aggregations
    AnnualizedSum = Aggregation('AnnualizedSum', _annualized_sum_batch)
    DailySum = Aggregation('DailySum', _daily_sum_batch)

    # Absolute value aggregations
    AbsSum = Aggregation(
        'AbsSum',
        lambda df: _ensure_frame_format(df).abs().sum(axis=0)
    )
    AbsMax = Aggregation(
        'AbsMax',
        lambda df: _ensure_frame_format(df).abs().max(axis=0)
    )
    AbsMean = Aggregation(
        'AbsMean',
        lambda df: _ensure_frame_format(df).abs().mean(axis=0)
    )
    AbsMin = Aggregation(
        'AbsMin',
        lambda df: _ensure_frame_format(df).abs().min(axis=0)
    )

    # Clipped aggregations (positive/negative only)
    SumGeqZero = Aggregation(
        'SumGeqZero',
        lambda df: _ensure_frame_format(df).clip(0, None).sum(axis=0)
    )
    SumLeqZero = Aggregation(
        'SumLeqZero',
        lambda df: _ensure_frame_format(df).clip(None, 0).sum(axis=0)
    )
    MeanGeqZero = Aggregation(
        'MeanGeqZero',
        lambda df: _ensure_frame_format(df).clip(0, None).mean(axis=0)
    )
    MeanLeqZero = Aggregation(
        'MeanLeqZero',
        lambda df: _ensure_frame_format(df).clip(None, 0).mean(axis=0)
    )

    # MTU (Market Time Unit) aggregations - count timesteps
    MTUsWithNaN = Aggregation(
        'MTUsWithNaN',
        lambda df: _ensure_frame_format(df).isna().sum(axis=0),
        Units.MTU
    )
    MTUsNonZero = Aggregation(
        'MTUsNonZero',
        lambda df: ((_ensure_frame_format(df) != 0) & ~_ensure_frame_format(df).isna()).sum(axis=0),
        Units.MTU
    )
    MTUsEqZero = Aggregation(
        'MTUsEqZero',
        lambda df: (_ensure_frame_format(df) == 0).sum(axis=0),
        Units.MTU
    )
    MTUsAboveZero = Aggregation(
        'MTUsAboveZero',
        lambda df: (_ensure_frame_format(df) > 0).sum(axis=0),
        Units.MTU
    )
    MTUsBelowZero = Aggregation(
        'MTUsBelowZero',
        lambda df: (_ensure_frame_format(df) < 0).sum(axis=0),
        Units.MTU
    )

    # Parameterized MTU aggregations
    @staticmethod
    def MTUsAboveX(x: float) -> Aggregation:
        """
        Count timesteps where value is above threshold.

        Args:
            x: Threshold value

        Returns:
            Aggregation that counts timesteps > x per column
        """
        return Aggregation(
            f'MTUsAbove{x}',
            lambda df: (_ensure_frame_format(df) > x).sum(axis=0),
            Units.MTU
        )

    @staticmethod
    def MTUsBelowX(x: float) -> Aggregation:
        """
        Count timesteps where value is below threshold.

        Args:
            x: Threshold value

        Returns:
            Aggregation that counts timesteps < x per column
        """
        return Aggregation(
            f'MTUsBelow{x}',
            lambda df: (_ensure_frame_format(df) < x).sum(axis=0),
            Units.MTU
        )

Sum class-attribute instance-attribute

Sum = Aggregation('Sum', lambda df: _column_wise_sum(_ensure_frame_format(df)))

Total class-attribute instance-attribute

Total = Aggregation('Total', lambda df: _column_wise_sum(_ensure_frame_format(df)))

Mean class-attribute instance-attribute

Mean = Aggregation('Mean', lambda df: mean(axis=0))

Max class-attribute instance-attribute

Max = Aggregation('Max', lambda df: max(axis=0))

Min class-attribute instance-attribute

Min = Aggregation('Min', lambda df: min(axis=0))

AnnualizedSum class-attribute instance-attribute

AnnualizedSum = Aggregation('AnnualizedSum', _annualized_sum_batch)

DailySum class-attribute instance-attribute

DailySum = Aggregation('DailySum', _daily_sum_batch)

AbsSum class-attribute instance-attribute

AbsSum = Aggregation('AbsSum', lambda df: sum(axis=0))

AbsMax class-attribute instance-attribute

AbsMax = Aggregation('AbsMax', lambda df: max(axis=0))

AbsMean class-attribute instance-attribute

AbsMean = Aggregation('AbsMean', lambda df: mean(axis=0))

AbsMin class-attribute instance-attribute

AbsMin = Aggregation('AbsMin', lambda df: min(axis=0))

SumGeqZero class-attribute instance-attribute

SumGeqZero = Aggregation('SumGeqZero', lambda df: sum(axis=0))

SumLeqZero class-attribute instance-attribute

SumLeqZero = Aggregation('SumLeqZero', lambda df: sum(axis=0))

MeanGeqZero class-attribute instance-attribute

MeanGeqZero = Aggregation('MeanGeqZero', lambda df: mean(axis=0))

MeanLeqZero class-attribute instance-attribute

MeanLeqZero = Aggregation('MeanLeqZero', lambda df: mean(axis=0))

MTUsWithNaN class-attribute instance-attribute

MTUsWithNaN = Aggregation('MTUsWithNaN', lambda df: sum(axis=0), MTU)

MTUsNonZero class-attribute instance-attribute

MTUsNonZero = Aggregation('MTUsNonZero', lambda df: sum(axis=0), MTU)

MTUsEqZero class-attribute instance-attribute

MTUsEqZero = Aggregation('MTUsEqZero', lambda df: sum(axis=0), MTU)

MTUsAboveZero class-attribute instance-attribute

MTUsAboveZero = Aggregation('MTUsAboveZero', lambda df: sum(axis=0), MTU)

MTUsBelowZero class-attribute instance-attribute

MTUsBelowZero = Aggregation('MTUsBelowZero', lambda df: sum(axis=0), MTU)

MTUsAboveX staticmethod

MTUsAboveX(x: float) -> Aggregation

Count timesteps where value is above threshold.

Parameters:

Name Type Description Default
x float

Threshold value

required

Returns:

Type Description
Aggregation

Aggregation that counts timesteps > x per column

Source code in submodules/mesqual/mesqual/kpis/aggregations.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
@staticmethod
def MTUsAboveX(x: float) -> Aggregation:
    """
    Count timesteps where value is above threshold.

    Args:
        x: Threshold value

    Returns:
        Aggregation that counts timesteps > x per column
    """
    return Aggregation(
        f'MTUsAbove{x}',
        lambda df: (_ensure_frame_format(df) > x).sum(axis=0),
        Units.MTU
    )

MTUsBelowX staticmethod

MTUsBelowX(x: float) -> Aggregation

Count timesteps where value is below threshold.

Parameters:

Name Type Description Default
x float

Threshold value

required

Returns:

Type Description
Aggregation

Aggregation that counts timesteps < x per column

Source code in submodules/mesqual/mesqual/kpis/aggregations.py
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
@staticmethod
def MTUsBelowX(x: float) -> Aggregation:
    """
    Count timesteps where value is below threshold.

    Args:
        x: Threshold value

    Returns:
        Aggregation that counts timesteps < x per column
    """
    return Aggregation(
        f'MTUsBelow{x}',
        lambda df: (_ensure_frame_format(df) < x).sum(axis=0),
        Units.MTU
    )

ValueComparisons

Standard comparison operations for KPIs.

Used to compare variation vs reference scenarios.

Example:

>>> ref_value = 100
>>> var_value = 120
>>> ValueComparisons.Increase(var_value, ref_value)  # 20
>>> ValueComparisons.PercentageIncrease(var_value, ref_value)  # 20.0
Source code in submodules/mesqual/mesqual/kpis/aggregations.py
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
class ValueComparisons:
    """
    Standard comparison operations for KPIs.

    Used to compare variation vs reference scenarios.

    Example:

        >>> ref_value = 100
        >>> var_value = 120
        >>> ValueComparisons.Increase(var_value, ref_value)  # 20
        >>> ValueComparisons.PercentageIncrease(var_value, ref_value)  # 20.0
    """

    Increase = ValueComparison("Increase", lambda var, ref: var - ref)
    Decrease = ValueComparison("Decrease", lambda var, ref: ref - var)
    PercentageIncrease = ValueComparison(
        "PercentageIncrease",
        lambda var, ref: np.inf * np.sign(var) if ref == 0 else (var - ref) / ref * 100,
        Units.percent
    )
    PercentageDecrease = ValueComparison(
        "PercentageDecrease",
        lambda var, ref: -1 * np.inf * np.sign(var) if ref == 0 else (ref - var) / ref * 100,
        Units.percent
    )
    Share = ValueComparison(
        "Share",
        lambda var, ref: np.inf * np.sign(var) if ref == 0 else var / ref * 100,
        Units.percent
    )
    Delta = ValueComparison("Delta", lambda var, ref: var - ref)
    Diff = ValueComparison("Diff", lambda var, ref: var - ref)

Increase class-attribute instance-attribute

Increase = ValueComparison('Increase', lambda var, ref: var - ref)

Decrease class-attribute instance-attribute

Decrease = ValueComparison('Decrease', lambda var, ref: ref - var)

PercentageIncrease class-attribute instance-attribute

PercentageIncrease = ValueComparison('PercentageIncrease', lambda var, ref: inf * sign(var) if ref == 0 else (var - ref) / ref * 100, percent)

PercentageDecrease class-attribute instance-attribute

PercentageDecrease = ValueComparison('PercentageDecrease', lambda var, ref: -1 * inf * sign(var) if ref == 0 else (ref - var) / ref * 100, percent)

Share class-attribute instance-attribute

Share = ValueComparison('Share', lambda var, ref: inf * sign(var) if ref == 0 else var / ref * 100, percent)

Delta class-attribute instance-attribute

Delta = ValueComparison('Delta', lambda var, ref: var - ref)

Diff class-attribute instance-attribute

Diff = ValueComparison('Diff', lambda var, ref: var - ref)

ArithmeticValueOperations

Standard arithmetic operations for KPIs.

Used to derive new KPI values from existing ones.

Example:

>>> value1 = 100
>>> value2 = 50
>>> ArithmeticValueOperations.Sum(value1, value2)  # 150
>>> ArithmeticValueOperations.Division(value1, value2)  # 2.0
Source code in submodules/mesqual/mesqual/kpis/aggregations.py
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
class ArithmeticValueOperations:
    """
    Standard arithmetic operations for KPIs.

    Used to derive new KPI values from existing ones.

    Example:

        >>> value1 = 100
        >>> value2 = 50
        >>> ArithmeticValueOperations.Sum(value1, value2)  # 150
        >>> ArithmeticValueOperations.Division(value1, value2)  # 2.0
    """

    Product = ArithmeticValueOperation("Product", lambda var, ref: var * ref)
    Division = ArithmeticValueOperation(
        "Division",
        lambda var, ref: np.inf * np.sign(var) if ref == 0 else var / ref
    )
    Share = ArithmeticValueOperation(
        "Share",
        lambda var, ref: np.inf * np.sign(var) if ref == 0 else var / ref * 100,
        Units.percent
    )
    Sum = ArithmeticValueOperation("Sum", lambda var, ref: var + ref)
    Diff = ArithmeticValueOperation("Diff", lambda var, ref: var - ref)
    Delta = ArithmeticValueOperation("Delta", lambda var, ref: var - ref)

Product class-attribute instance-attribute

Product = ArithmeticValueOperation('Product', lambda var, ref: var * ref)

Division class-attribute instance-attribute

Division = ArithmeticValueOperation('Division', lambda var, ref: inf * sign(var) if ref == 0 else var / ref)

Share class-attribute instance-attribute

Share = ArithmeticValueOperation('Share', lambda var, ref: inf * sign(var) if ref == 0 else var / ref * 100, percent)

Sum class-attribute instance-attribute

Sum = ArithmeticValueOperation('Sum', lambda var, ref: var + ref)

Diff class-attribute instance-attribute

Diff = ArithmeticValueOperation('Diff', lambda var, ref: var - ref)

Delta class-attribute instance-attribute

Delta = ArithmeticValueOperation('Delta', lambda var, ref: var - ref)

Aggregation dataclass

Aggregation function for batch KPI computation.

Unlike the old system, these aggregations:

- Operate on entire DataFrames
- Return Series with one value per column (one per object)
- Enable batch computation across all objects

Attributes:

Name Type Description
name str

Human-readable name of the aggregation

agg Callable[[DataFrame], Series]

Function that takes DataFrame and returns Series

unit Unit

Optional unit override (e.g., MTU for time-based counts)

Source code in submodules/mesqual/mesqual/kpis/aggregations.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@dataclass
class Aggregation:
    """
    Aggregation function for batch KPI computation.

    Unlike the old system, these aggregations:

        - Operate on entire DataFrames
        - Return Series with one value per column (one per object)
        - Enable batch computation across all objects

    Attributes:
        name: Human-readable name of the aggregation
        agg: Function that takes DataFrame and returns Series
        unit: Optional unit override (e.g., MTU for time-based counts)
    """
    name: str
    agg: Callable[[pd.DataFrame], pd.Series]
    unit: Units.Unit = None

    def __call__(self, df: pd.DataFrame) -> pd.Series:
        """Apply aggregation to DataFrame, return Series with one value per column."""
        return self.agg(df)

    def __str__(self):
        return self.name

    def __hash__(self):
        return hash(self.name)

    def __eq__(self, other) -> bool:
        return isinstance(other, Aggregation) and self.name == other.name

name instance-attribute

name: str

agg instance-attribute

agg: Callable[[DataFrame], Series]

unit class-attribute instance-attribute

unit: Unit = None

__init__

__init__(name: str, agg: Callable[[DataFrame], Series], unit: Unit = None) -> None

__call__

__call__(df: DataFrame) -> Series

Apply aggregation to DataFrame, return Series with one value per column.

Source code in submodules/mesqual/mesqual/kpis/aggregations.py
33
34
35
def __call__(self, df: pd.DataFrame) -> pd.Series:
    """Apply aggregation to DataFrame, return Series with one value per column."""
    return self.agg(df)

__str__

__str__()
Source code in submodules/mesqual/mesqual/kpis/aggregations.py
37
38
def __str__(self):
    return self.name

__hash__

__hash__()
Source code in submodules/mesqual/mesqual/kpis/aggregations.py
40
41
def __hash__(self):
    return hash(self.name)

__eq__

__eq__(other) -> bool
Source code in submodules/mesqual/mesqual/kpis/aggregations.py
43
44
def __eq__(self, other) -> bool:
    return isinstance(other, Aggregation) and self.name == other.name

OperationOfTwoValues dataclass

Operation that combines two scalar values.

Used for comparison KPIs (e.g., difference between scenarios) and arithmetic operations between KPI values.

Attributes:

Name Type Description
name str

Human-readable name of the operation

agg Callable[[float | int, float | int], float | int]

Function that takes two scalars and returns a scalar

unit Unit

Optional unit override

Source code in submodules/mesqual/mesqual/kpis/aggregations.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
@dataclass
class OperationOfTwoValues:
    """
    Operation that combines two scalar values.

    Used for comparison KPIs (e.g., difference between scenarios)
    and arithmetic operations between KPI values.

    Attributes:
        name: Human-readable name of the operation
        agg: Function that takes two scalars and returns a scalar
        unit: Optional unit override
    """
    name: str
    agg: Callable[[float | int, float | int], float | int]
    unit: Units.Unit = None

    def __call__(self, variation_value: float | int, reference_value: float | int) -> float | int:
        """Apply operation to two values."""
        return self.agg(variation_value, reference_value)

    def __str__(self):
        return self.name

    def __hash__(self):
        return hash(self.name)

    def __eq__(self, other) -> bool:
        return isinstance(other, OperationOfTwoValues) and self.name == other.name

name instance-attribute

name: str

agg instance-attribute

agg: Callable[[float | int, float | int], float | int]

unit class-attribute instance-attribute

unit: Unit = None

__init__

__init__(name: str, agg: Callable[[float | int, float | int], float | int], unit: Unit = None) -> None

__call__

__call__(variation_value: float | int, reference_value: float | int) -> float | int

Apply operation to two values.

Source code in submodules/mesqual/mesqual/kpis/aggregations.py
268
269
270
def __call__(self, variation_value: float | int, reference_value: float | int) -> float | int:
    """Apply operation to two values."""
    return self.agg(variation_value, reference_value)

__str__

__str__()
Source code in submodules/mesqual/mesqual/kpis/aggregations.py
272
273
def __str__(self):
    return self.name

__hash__

__hash__()
Source code in submodules/mesqual/mesqual/kpis/aggregations.py
275
276
def __hash__(self):
    return hash(self.name)

__eq__

__eq__(other) -> bool
Source code in submodules/mesqual/mesqual/kpis/aggregations.py
278
279
def __eq__(self, other) -> bool:
    return isinstance(other, OperationOfTwoValues) and self.name == other.name

ValueComparison dataclass

Bases: OperationOfTwoValues

Comparison operation between two KPI values (e.g., difference, percentage change).

Source code in submodules/mesqual/mesqual/kpis/aggregations.py
282
283
284
class ValueComparison(OperationOfTwoValues):
    """Comparison operation between two KPI values (e.g., difference, percentage change)."""
    pass

ArithmeticValueOperation dataclass

Bases: OperationOfTwoValues

Arithmetic operation between two KPI values (e.g., sum, product).

Source code in submodules/mesqual/mesqual/kpis/aggregations.py
322
323
324
class ArithmeticValueOperation(OperationOfTwoValues):
    """Arithmetic operation between two KPI values (e.g., sum, product)."""
    pass