mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-29 18:17:43 +00:00
177 lines
6.8 KiB
Markdown
177 lines
6.8 KiB
Markdown
# MPE: Mean Percentage Error
|
||
|
||
> *MAPE tells you how wrong you are; MPE tells you which direction you're wrong in.*
|
||
|
||
| Property | Value |
|
||
| ---------------- | -------------------------------- |
|
||
| **Category** | Error Metric |
|
||
| **Inputs** | Actual, Predicted (dual series) |
|
||
| **Parameters** | `period` |
|
||
| **Outputs** | Single series (MPE) |
|
||
| **Output range** | Any (positive or negative) |
|
||
| **Warmup** | `period` bars |
|
||
| **PineScript** | [mpe.pine](mpe.pine) |
|
||
|
||
- Mean Percentage Error measures the average percentage difference between actual and predicted values while preserving the sign.
|
||
- **Similar:** [ME](../me/Me.md), [MAPE](../mape/Mape.md) | **Trading note:** Mean Percentage Error; reveals directional bias as percentage. Positive/negative cancellation is a feature.
|
||
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
||
|
||
Mean Percentage Error measures the average percentage difference between actual and predicted values while preserving the sign. Unlike MAPE, which takes absolute values, MPE reveals systematic bias in predictions—whether a model consistently over-predicts or under-predicts.
|
||
|
||
## Architecture & Physics
|
||
|
||
MPE computes the signed percentage error for each data point and averages over a rolling window:
|
||
|
||
$$\text{MPE} = \frac{100}{n} \sum_{i=1}^{n} \frac{(\text{actual}_i - \text{predicted}_i)}{\text{actual}_i}$$
|
||
|
||
The sign preservation makes MPE invaluable for bias detection:
|
||
|
||
* **Positive MPE**: Model systematically under-predicts (actual > predicted)
|
||
* **Negative MPE**: Model systematically over-predicts (actual < predicted)
|
||
* **MPE near zero**: No systematic bias (though individual errors may be large)
|
||
|
||
### Bias Detection
|
||
|
||
Consider a weather forecasting model:
|
||
|
||
* If MPE = +15%, the model consistently predicts temperatures 15% lower than actual
|
||
* If MPE = -10%, the model consistently predicts temperatures 10% higher than actual
|
||
* If MPE ≈ 0% but MAPE = 20%, errors cancel out (no bias) but magnitude is still significant
|
||
|
||
## Mathematical Foundation
|
||
|
||
### 1. Point-wise Percentage Error
|
||
|
||
For each observation:
|
||
|
||
$$e_i = 100 \times \frac{\text{actual}_i - \text{predicted}_i}{\text{actual}_i}$$
|
||
|
||
### 2. Rolling Average
|
||
|
||
Over a period $n$:
|
||
|
||
$$\text{MPE}_t = \frac{1}{n} \sum_{i=t-n+1}^{t} e_i$$
|
||
|
||
### 3. Relationship to MAPE
|
||
|
||
$$\text{MAPE} = \frac{100}{n} \sum |e_i / 100|$$
|
||
$$\text{MPE} = \frac{100}{n} \sum (e_i / 100)$$
|
||
|
||
When errors are consistently in one direction: $|\text{MPE}| \approx \text{MAPE}$
|
||
When errors alternate: $|\text{MPE}| < \text{MAPE}$
|
||
|
||
## Performance Profile
|
||
|
||
### Operation Count (Streaming Mode)
|
||
|
||
O(1) per bar. Single-pass scalar transformation of (actual, forecast) pair; no lookback window required.
|
||
|
||
| Operation | Count | Cost (cycles) | Subtotal |
|
||
| :--- | :---: | :---: | :---: |
|
||
| Error computation (subtract, abs/square/log) | 1-3 | ~3-8 cy | ~5-15 cy |
|
||
| Running accumulator update (EMA or sum) | 1 | ~4 cy | ~4 cy |
|
||
| **Total** | **2-4** | — | **~9-19 cycles** |
|
||
|
||
Streaming update requires only the current actual/forecast pair and running state. ~10-15 cycles/bar typical.
|
||
|
||
### Batch Mode (SIMD Analysis)
|
||
|
||
| Operation | Vectorizable? | Notes |
|
||
| :--- | :---: | :--- |
|
||
| Element-wise error computation | Yes | Independent per bar; fully vectorizable with `Vector<double>` |
|
||
| Reduction (sum/mean) | Yes | Parallel reduction; AVX2 gives 4x speedup |
|
||
| Log/exp components | Partial | Transcendental ops; polynomial approx for SIMD |
|
||
|
||
Batch SIMD: 4x-8x speedup for large windows. ~3-5 cy/bar amortized in vectorized batch mode.
|
||
|
||
| Metric | Score | Notes |
|
||
| :--- | :--- | :--- |
|
||
| **Throughput** | 15 ns/bar | O(1) via running sum |
|
||
| **Allocations** | 0 | Zero-allocation hot path |
|
||
| **Complexity** | O(1) | Constant per update |
|
||
| **Bias Detection** | 10/10 | Primary strength |
|
||
| **Magnitude Info** | 3/10 | Errors can cancel |
|
||
| **Scale Independence** | 9/10 | Percentage-based |
|
||
| **Outlier Sensitivity** | 5/10 | Linear in error magnitude |
|
||
|
||
## Usage
|
||
|
||
```csharp
|
||
// Streaming mode - bias detection in real-time
|
||
var mpe = new Mpe(20);
|
||
|
||
// Actual values consistently higher than predictions
|
||
mpe.Update(actual: 105.0, predicted: 100.0); // +5%
|
||
mpe.Update(actual: 110.0, predicted: 100.0); // +10%
|
||
// MPE will be positive, indicating under-prediction bias
|
||
|
||
double currentBias = mpe.Last.Value;
|
||
if (currentBias > 5.0)
|
||
Console.WriteLine("Model is under-predicting by {0:F1}%", currentBias);
|
||
else if (currentBias < -5.0)
|
||
Console.WriteLine("Model is over-predicting by {0:F1}%", Math.Abs(currentBias));
|
||
else
|
||
Console.WriteLine("Model shows no significant bias");
|
||
|
||
// Batch mode - analyze historical predictions
|
||
var actual = new TSeries { 100, 105, 98, 102, 101 };
|
||
var predicted = new TSeries { 95, 100, 95, 100, 100 };
|
||
var results = Mpe.Calculate(actual, predicted, period: 3);
|
||
|
||
// Span mode - zero-allocation bulk processing
|
||
Span<double> output = stackalloc double[1000];
|
||
Mpe.Batch(actualSpan, predictedSpan, output, period: 20);
|
||
```
|
||
|
||
## Interpretation Guide
|
||
|
||
| MPE Value | Interpretation | Action |
|
||
| :--- | :--- | :--- |
|
||
| **> +10%** | Severe under-prediction | Add positive bias correction |
|
||
| **+5% to +10%** | Moderate under-prediction | Consider model recalibration |
|
||
| **-5% to +5%** | Acceptable bias range | Monitor for drift |
|
||
| **-10% to -5%** | Moderate over-prediction | Consider model recalibration |
|
||
| **< -10%** | Severe over-prediction | Add negative bias correction |
|
||
|
||
## Comparison with Related Metrics
|
||
|
||
| Metric | Formula | Preserves Sign | Use Case |
|
||
| :--- | :--- | :--- | :--- |
|
||
| **MPE** | 100 × (A-P)/A | ✓ | Bias detection |
|
||
| **MAPE** | 100 × \|A-P\|/A | ✗ | Magnitude only |
|
||
| **ME** | A - P | ✓ | Absolute bias |
|
||
| **MAE** | \|A - P\| | ✗ | Absolute magnitude |
|
||
|
||
## Common Pitfalls
|
||
|
||
### 1. Zero Actuals
|
||
|
||
MPE is undefined when actual = 0. The implementation uses epsilon fallback:
|
||
|
||
```csharp
|
||
double divisor = Math.Abs(actual) < 1e-10 ? 1e-10 : actual;
|
||
```
|
||
|
||
### 2. Cancellation Effect
|
||
|
||
Errors of opposite signs cancel out. A model alternating between +50% and -50% errors would show MPE ≈ 0%, masking severe inaccuracy.
|
||
|
||
**Solution**: Use MPE alongside MAPE:
|
||
|
||
* Low MAPE + Low |MPE|: Good model
|
||
* Low MAPE + High |MPE|: Unlikely (mathematically constrained)
|
||
* High MAPE + Low |MPE|: High variance, no bias
|
||
* High MAPE + High |MPE|: High variance with bias
|
||
|
||
### 3. Asymmetric Bounds
|
||
|
||
Unlike MAPE (bounded at 0% to ∞), MPE can range from -∞ to +100%:
|
||
|
||
* Maximum positive: actual = 100, predicted = 0 → MPE = +100%
|
||
* No upper bound on negative: actual = 100, predicted = 1000 → MPE = -900%
|
||
|
||
## See Also
|
||
|
||
* [MAPE](../mape/Mape.md) - Unsigned percentage error for magnitude
|
||
* [ME](../me/Me.md) - Signed absolute error for absolute bias
|
||
* [MAE](../mae/Mae.md) - Unsigned absolute error for magnitude |