Measure spread as the average absolute distance each value sits from the mean. Compute the mean, then average the absolute deviations — dividing by n (not n−1). By hand, two loops: one for the mean, one for the sum of absolute deviations. With numpy, np.mean(np.abs(x - np.mean(x))) does both in one vectorised expression.

By hand

First loop: accumulate total for the mean. Second loop: accumulate abs_sum = sum(abs(v - mean)). Divide by n (total count, no Bessel correction — MAD uses n by definition). With mean=8.0 and absolute deviations [4, 0, 2, 5, 2, 2, 1] summing to 16, MAD = 16/7 ≈ 2.2857.

naive.py
Replay: real traced execution (multi-file project)
values = [4, 8, 6, 13, 10, 6, 9]
n = len(values)
total = 0.0
for v in values:
    total = total + v
mean = total / n
abs_sum = 0.0
for v in values:
    abs_sum = abs_sum + abs(v - mean)
mad = abs_sum / n
print('RESULT:', round(mad, 10))
  1. values ← [4, 8, 6, 13, 10, 6, 9]

    1values = [4, 8, 6, 13, 10, 6, 9]2n = len(values)
    values this step[4, 8, 6, 13, 10, 6, 9]values
  2. n ← 7

    1values = [4, 8, 6, 13, 10, 6, 9]2n = len(values)3total = 0.0
    values this step7n
  3. total ← 0.0

    2n = len(values)3total = 0.04for v in values:
    values this step0.0total
  4. v ← 4, total ← 4.0

    pass 1 of 7
    3total = 0.04for v in values:5    total = total + v6mean = total / n
    values this step4v0.0 4.0total
    All 7 passes — pass 1 is the card above
    passvtotal
    140.0 4.0
    24 84.0 12.0
    38 612.0 18.0
    46 1318.0 31.0
    513 1031.0 41.0
    610 641.0 47.0
    76 947.0 56.0
  5. for v in values:

    3total = 0.04for v in values:5    total = total + v
  6. mean ← 8.0

    5    total = total + v6mean = total / n7abs_sum = 0.0
    values this step8.0mean
  7. abs_sum ← 0.0

    6mean = total / n7abs_sum = 0.08for v in values:
    values this step0.0abs_sum
  8. v ← 4, abs_sum ← 4.0

    pass 1 of 7
    7abs_sum = 0.08for v in values:9    abs_sum = abs_sum + abs(v - mean)10mad = abs_sum / n
    values this step9 4v0.0 4.0abs_sum
    All 7 passes — pass 1 is the card above
    passvabs_sum
    19 40.0 4.0
    24 8
    38 64.0 6.0
    46 136.0 11.0
    513 1011.0 13.0
    610 613.0 15.0
    76 915.0 16.0
  9. for v in values:

    7abs_sum = 0.08for v in values:9    abs_sum = abs_sum + abs(v - mean)
  10. mad ← 2.2857142857142856

    9    abs_sum = abs_sum + abs(v - mean)10mad = abs_sum / n11print('RESULT:', round(mad, 10))
    values this step2.2857142857142856mad
  11. stdout ← RESULT: 2.2857142857

    10mad = abs_sum / n11print('RESULT:', round(mad, 10))
    values this stepRESULT: 2.2857142857stdout

With the library

np.abs(x - x_mean) subtracts the mean from every element and takes the absolute value in one vectorised step; np.mean(...) then averages the result. Both halves divide by n, so the results match exactly.

library.py
import numpy as np
from dalib.display import set_display
set_display()

values = [4, 8, 6, 13, 10, 6, 9]
x = np.array(values, dtype=float)
x_mean = float(np.mean(x))
mad = float(np.mean(np.abs(x - x_mean)))
print('mean:', x_mean)
print('RESULT:', round(mad, 10))
mean: 8.0
RESULT: 2.2857142857

Implementation notes

  • MAD divides by n (the full count), not n−1. There is no Bessel correction because MAD is not trying to estimate a population parameter in the same way variance is.
  • MAD is in the same units as the data (like std) but is more robust to outliers because absolute differences grow linearly while squared differences grow quadratically.
  • statistics.mean(abs(v - mean) for v in values) is the pure-stdlib equivalent, but numpy's vectorised form is faster for large arrays.