# Power BI measure definitions

These DAX measures respect report filter context. Currency is GBP for retail; demand errors are rentals per observed hour. DAX has not been evaluated by a local Power BI engine.

## Observed Hours

Observed held-out hours; absent target hours do not become zero-rental observations.

```dax
Observed Hours =
COALESCE ( COUNTROWS ( FactForecast ), 0 )
```

Format: `#,0`

## Expected Hours

Selected calendar dates multiplied by selected hours of day.

```dax
Expected Hours =
COUNTROWS ( VALUES ( DimDate[DateKey] ) ) * COUNTROWS ( VALUES ( DimHour[HourKey] ) )
```

Format: `#,0`

## Missing Hours

Missing target observations within selected calendar/hour dimensions.

```dax
Missing Hours =
[Expected Hours] - [Observed Hours]
```

Format: `#,0`

## Observation Coverage

Observed versus expected calendar hours; preserves source gaps.

```dax
Observation Coverage =
DIVIDE ( [Observed Hours], [Expected Hours] )
```

Format: `0.0%`

## Actual Rentals

Realized rentals summed once per observed timestamp.

```dax
Actual Rentals =
SUM ( FactForecast[ActualRentals] )
```

Format: `#,0`

## Model Forecast

Gradient-boosting forecast, on observed target hours only.

```dax
Model Forecast =
SUM ( FactForecast[ModelForecast] )
```

Format: `#,0`

## Baseline Forecast

Validation-selected previous-week baseline, on matched observed target hours.

```dax
Baseline Forecast =
SUM ( FactForecast[BaselineForecast] )
```

Format: `#,0`

## Model MAE

Mean absolute error in rentals per observed hour.

```dax
Model MAE =
AVERAGE ( FactForecast[ModelAbsoluteError] )
```

Format: `0.00`

## Baseline MAE

Baseline mean absolute error on the same observations.

```dax
Baseline MAE =
AVERAGE ( FactForecast[BaselineAbsoluteError] )
```

Format: `0.00`

## MAE Improvement

Relative error reduction; negative values mean deterioration.

```dax
MAE Improvement =
DIVIDE ( [Baseline MAE] - [Model MAE], [Baseline MAE] )
```

Format: `0.0%`

## Model WAPE

Total absolute error divided by actual rentals; not forecast accuracy.

```dax
Model WAPE =
DIVIDE ( SUM ( FactForecast[ModelAbsoluteError] ), [Actual Rentals] )
```

Format: `0.0%`

## Model RMSE

Root mean squared error in rentals per observed hour.

```dax
Model RMSE =
SQRT ( AVERAGE ( FactForecast[ModelSquaredError] ) )
```

Format: `0.00`

## Forecast Bias

Forecast minus actual rentals. A negative value means underprediction.

```dax
Forecast Bias =
AVERAGE ( FactForecast[ModelError] )
```

Format: `0.00`

## Underpredicted Hours

Observed hours in which forecast is strictly below actual demand.

```dax
Underpredicted Hours =
SUM ( FactForecast[Underpredicted] )
```

Format: `#,0`

## Underprediction Share

Proportion of observed hours with underprediction.

```dax
Underprediction Share =
DIVIDE ( [Underpredicted Hours], [Observed Hours] )
```

Format: `0.0%`

## Underprediction Amount

Sum of positive actual-minus-forecast gaps. Not unmet demand or capacity need.

```dax
Underprediction Amount =
SUM ( FactForecast[UnderpredictionAmount] )
```

Format: `#,0`

## Overprediction Amount

Sum of positive forecast-minus-actual gaps. Not unused physical inventory.

```dax
Overprediction Amount =
SUM ( FactForecast[OverpredictionAmount] )
```

Format: `#,0`
