Measure how spread out the data is. Compute the mean, then average the squared deviations from it — dividing by n−1 (Bessel's correction) to get an unbiased estimate of the population variance. By hand, two loops: one for the mean, one for the squared deviations. With the library, statistics.variance uses the same n−1 denominator.

By hand

First loop: accumulate total to compute mean. Second loop: accumulate sq_diff = sum((v - mean)**2). Divide by n - 1 (not n) to produce the sample variance. With n=7 values, mean=8.0, and sq_diff=54.0, the result is 54 / 6 = 9.0.

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
sq_diff = 0.0
for v in values:
    sq_diff = sq_diff + (v - mean) ** 2
variance = sq_diff / (n - 1)
print('RESULT:', round(variance, 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 / n7sq_diff = 0.0
    values this step8.0mean
  7. sq_diff ← 0.0

    6mean = total / n7sq_diff = 0.08for v in values:
    values this step0.0sq_diff
  8. v ← 4, sq_diff ← 16.0

    pass 1 of 7
    7sq_diff = 0.08for v in values:9    sq_diff = sq_diff + (v - mean) ** 210variance = sq_diff / (n - 1)
    values this step9 4v0.0 16.0sq_diff
    All 7 passes — pass 1 is the card above
    passvsq_diff
    19 40.0 16.0
    24 8
    38 616.0 20.0
    46 1320.0 45.0
    513 1045.0 49.0
    610 649.0 53.0
    76 953.0 54.0
  9. for v in values:

    7sq_diff = 0.08for v in values:9    sq_diff = sq_diff + (v - mean) ** 2
  10. variance ← 9.0

    9    sq_diff = sq_diff + (v - mean) ** 210variance = sq_diff / (n - 1)11print('RESULT:', round(variance, 10))
    values this step9.0variance
  11. stdout ← RESULT: 9.0

    10variance = sq_diff / (n - 1)11print('RESULT:', round(variance, 10))
    values this stepRESULT: 9.0stdout

With the library

statistics.variance uses n−1 and matches the naive result exactly. np.var defaults to ddof=0 (population variance, divides by n) — pass ddof=1 to get the sample variance. The snapshot shows all three side by side to make the ddof difference concrete.

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

values = [4, 8, 6, 13, 10, 6, 9]
var_stdlib = float(statistics.variance(values))
var_np_pop = float(np.var(values))
var_np_samp = float(np.var(values, ddof=1))
print('statistics.variance:', var_stdlib)
print('np.var (ddof=0):    ', round(var_np_pop, 4))
print('np.var (ddof=1):    ', var_np_samp)
print('RESULT:', round(var_stdlib, 10))
statistics.variance: 9.0
np.var (ddof=0):     7.7143
np.var (ddof=1):     9.0
RESULT: 9.0

Implementation notes

  • Dividing by n−1 instead of n is Bessel's correction: the sample mean slightly underestimates deviations from the true population mean, so shrinking the denominator compensates. Dividing by n gives the population variance, which is correct only when you have the full population.
  • np.var default is ddof=0 (population). Always pass ddof=1 when you want sample variance from numpy.
  • statistics.variance always uses n−1; there is no ddof parameter.