Compute the sample standard deviation — the square root of the sample variance. Standard deviation is in the same units as the data, making it more interpretable than variance. By hand, compute the sample variance (dividing by n−1) then take the square root. With the library, statistics.stdev does both steps with the same n−1 denominator.

By hand

With the library

statistics.stdev uses n−1 and matches math.sqrt(statistics.variance(values)) exactly. np.std defaults to ddof=0 (population std) — pass ddof=1 for the sample std. The snapshot shows both numpy variants alongside the stdlib result to make the ddof trap visible.

naive.py
import math
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
std = math.sqrt(sq_diff / (n - 1))
print('RESULT:', round(std, 10))
library.py
import statistics
import numpy as np
from dalib.display import set_display
set_display()

values = [4, 8, 6, 13, 10, 6, 9]
std_stdlib = float(statistics.stdev(values))
std_np_pop = float(np.std(values))
std_np_samp = float(np.std(values, ddof=1))
print('statistics.stdev:', std_stdlib)
print('np.std (ddof=0): ', round(std_np_pop, 4))
print('np.std (ddof=1): ', std_np_samp)
print('RESULT:', round(std_stdlib, 10))
statistics.stdev: 3.0
np.std (ddof=0):  2.7775
np.std (ddof=1):  3.0
RESULT: 3.0

Implementation notes

  • np.std default is ddof=0 (population std, divides by n under the square root). Pass ddof=1 whenever you want the sample std from numpy.
  • statistics.stdev always uses n−1; there is no ddof parameter.
  • Standard deviation is in the same units as the original values (here, whatever unit the values represent). Variance is in squared units, which is why std is more commonly reported.
  • Cross-reference: sample-variance (this chapter) for the squared version and a detailed explanation of Bessel's correction.