Variation
Z-Scores
Standardize each value as its distance from the mean in standard-deviation
units: z = (x − mean) / std. Z-scores let you compare values across
datasets with different scales. By hand, three loops: mean, then sample std
(ddof=1), then one z-score per element. With scipy, stats.zscore(values, ddof=1) computes all z-scores in one vectorised call.
By hand
Loop 1: mean. Loop 2: sample std (ddof=1, dividing by n−1 — same as
statistics.stdev). Loop 3: for each value, compute and append
round((v - mean) / std, 4). With mean=8.0 and std=3.0 the z-scores are
exact fractions of 1/3: −4/3, 0, −2/3, 5/3, 2/3, −2/3, 1/3.
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))
result = []
for v in values:
result.append(round((v - mean) / std, 4))
print('RESULT:', result)
import math
1import math2values = [4, 8, 6, 13, 10, 6, 9]values ← [4, 8, 6, 13, 10, 6, 9]
1import math2values = [4, 8, 6, 13, 10, 6, 9]3n = len(values)values this step[4, 8, 6, 13, 10, 6, 9]valuesn ← 7
2values = [4, 8, 6, 13, 10, 6, 9]3n = len(values)4total = 0.0values this step7ntotal ← 0.0
3n = len(values)4total = 0.05for v in values:values this step0.0totalv ← 4, total ← 4.0
pass 1 of 74total = 0.05for v in values:6 total = total + v7mean = total / nvalues this step4v0.0 → 4.0totalAll 7 passes — pass 1 is the card above pass vtotal1 4 0.0 → 4.0 2 4 → 8 4.0 → 12.0 3 8 → 6 12.0 → 18.0 4 6 → 13 18.0 → 31.0 5 13 → 10 31.0 → 41.0 6 10 → 6 41.0 → 47.0 7 6 → 9 47.0 → 56.0 for v in values:
4total = 0.05for v in values:6 total = total + vmean ← 8.0
6 total = total + v7mean = total / n8sq_diff = 0.0values this step8.0meansq_diff ← 0.0
7mean = total / n8sq_diff = 0.09for v in values:values this step0.0sq_diffv ← 4, sq_diff ← 16.0
pass 1 of 78sq_diff = 0.09for v in values:10 sq_diff = sq_diff + (v - mean) ** 211std = math.sqrt(sq_diff / (n - 1))values this step9 → 4v0.0 → 16.0sq_diffAll 7 passes — pass 1 is the card above pass vsq_diff1 9 → 4 0.0 → 16.0 2 4 → 8 — 3 8 → 6 16.0 → 20.0 4 6 → 13 20.0 → 45.0 5 13 → 10 45.0 → 49.0 6 10 → 6 49.0 → 53.0 7 6 → 9 53.0 → 54.0 for v in values:
8sq_diff = 0.09for v in values:10 sq_diff = sq_diff + (v - mean) ** 2std ← 3.0
10 sq_diff = sq_diff + (v - mean) ** 211std = math.sqrt(sq_diff / (n - 1))12result = []values this step3.0stdresult ← []
11std = math.sqrt(sq_diff / (n - 1))12result = []13for v in values:values this step[]resultv ← 4, result ← [-1.3333]
pass 1 of 712result = []13for v in values:14 result.append(round((v - mean) / std, 4))15print('RESULT:', result)values this step9 → 4v[] → [-1.3333]resultAll 7 passes — pass 1 is the card above pass vresult1 9 → 4 [] → [-1.3333] 2 4 → 8 [-1.3333] → [-1.3333, 0.0] 3 8 → 6 [-1.3333, 0.0] → [-1.3333, 0.0, -0.6667] 4 6 → 13 [-1.3333, 0.0, -0.6667] → [-1.3333, 0.0, -0.6667, 1.6667] 5 13 → 10 [-1.3333, 0.0, -0.6667, 1.6667] → [-1.3333, 0.0, -0.6667, 1.6667, 0.6667] 6 10 → 6 [-1.3333, 0.0, -0.6667, 1.6667, 0.6667] → [-1.3333, 0.0, -0.6667, 1.6667, 0.6667, -0.6667] 7 6 → 9 [-1.3333, 0.0, -0.6667, 1.6667, 0.6667, -0.6667] → [-1.3333, 0.0, -0.6667, 1.6667, 0.6667, -0.6667, 0.3333] for v in values:
12result = []13for v in values:14 result.append(round((v - mean) / std, 4))stdout ← RESULT: [-1.3333, 0.0, -0.6667, 1.6667, 0.6667, -0.6667, 0.3333]
14 result.append(round((v - mean) / std, 4))15print('RESULT:', result)values this stepRESULT: [-1.3333, 0.0, -0.6667, 1.6667, 0.6667, -0.6667, 0.3333]stdout
With the library
scipy.stats.zscore defaults to ddof=0 (population std). Passing
ddof=1 makes it use the sample std, matching the naive half. The snapshot
shows mean and std so the denominator choice is visible.
import numpy as np
from scipy import stats
from dalib.display import set_display
set_display()
values = [4, 8, 6, 13, 10, 6, 9]
z = stats.zscore(values, ddof=1)
result = [round(float(v), 4) for v in z]
print('mean:', float(np.mean(values)))
print('std (ddof=1):', round(float(np.std(values, ddof=1)), 4))
print('RESULT:', result)
mean: 8.0
std (ddof=1): 3.0
RESULT: [-1.3333, 0.0, -0.6667, 1.6667, 0.6667, -0.6667, 0.3333]
Implementation notes
scipy.stats.zscoredefaults toddof=0— always passddof=1explicitly when you want sample-std standardization to matchstatistics.stdevornp.std(ddof=1).- Z-scores sum to 0 and have mean 0; their sample std (ddof=1,
np.std(z, ddof=1)) equals 1.0. The population std (ddof=0) is less than 1 for any finite sample. Usenp.std(z, ddof=1)to verify. - Cross-reference:
standard-deviation(this chapter) for the ddof details;zscore-flag(python-data-cleaning ch06) for applying z-scores to outlier detection.