Chapter 6 — Data collection and analysis
Lesson map
Lesson 06 published. Map, example, EX033.
flowchart TD
N0["Learning outcomes"]
N1["6.1 Running the main study"]
N2["6.2 Data-quality checks"]
N3["6.3 Primary analysis"]
N4["6.4 Secondary outcomes and costs"]
N5["6.6 Practice activities"]
N6["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6
N6 --> EX["Worked example"]
EX --> Q["Exercise EX033"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["6.1 Running the main study"]
N2["6.2 Data-quality checks"]
N3["6.3 Primary analysis"]
N4["6.4 Secondary outcomes and costs"]
N5["6.6 Practice activities"]
N6["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> Q["EX033"]
[Learning outcomes]
|
v
[6.1 Running the main study]
|
v
[6.2 Data-quality checks]
|
v
[6.3 Primary analysis]
|
v
[6.4 Secondary outcomes and costs]
|
v
[6.6 Practice activities]
|
v
[Synthesis]
|
v
[Worked example] --> [Exercise EX033]
Learning outcomes
You will (1) run the main experiments exactly as planned and log deviations; (2) check data quality before analysis; (3) compute primary outcomes with uncertainty (Wilson intervals, bootstrap, variation across seeds); (4) analyse paired comparisons and secondary outcomes; and (5) present results in tables and figures that answer the research question.
6.1 Running the main study
Freeze code at a tagged commit, lock the configuration files, and run conditions in an interleaved or randomised order so that time-dependent problems (a node slowing down, a library update) do not align with one condition. Each run writes a record: condition, seed, config hash, start and end time, metrics and paths to raw outputs. Keep a deviation log as in the pilot. Leo's runs were interleaved by condition and seed, and his deviation log recorded the missing seed-4 run and its rerun. Check the log before analysis, not after.
6.2 Data-quality checks
Before computing anything, check: are all expected runs present? Do canary checks pass (the undefended model must be attackable; a model trained on shuffled labels should perform at chance)? Are there duplicates across splits? Are metric values within plausible ranges? These checks catch bugs that would otherwise become "findings". Leo's checks found one missing seed-4 run, which was rerun and logged before analysis. Write the checks as a script so they run the same way each time, and keep their output with the results.
6.3 Primary analysis
Compute the primary outcome per condition with intervals. For rates, use Wilson intervals; for metrics averaged over items, bootstrap over items; report variation across seeds separately. For paired comparisons (same records or prompts across conditions), bootstrap the difference. Follow the analysis plan; label any extra analysis as exploratory. When several comparisons are made, correct for multiplicity or present them as exploratory. The lab below demonstrates the three tools. With 3 of 20 successes, the Wilson interval spans 5% to 36%: such a small sample cannot support a precise claim. The per-seed rates show seed-to-seed spread. The paired bootstrap estimates the reduction of a defence on the same prompts with an interval excluding zero.
"""Lab S: reporting attack-success rates honestly: Wilson intervals,
seed variation and a paired bootstrap. Synthetic trial outcomes only."""
import math, random
def wilson(k, n, z=1.96):
p = k/n; d = 1 + z*z/n
c = (p + z*z/(2*n))/d; h = z*math.sqrt(p*(1-p)/n + z*z/(4*n*n))/d
return c - h, c + h
for k, n in ((3, 20), (30, 200), (300, 2000)):
lo, hi = wilson(k, n); print(f"successes={k}/{n} rate={k/n:.3f} wilson95=[{lo:.3f}, {hi:.3f}]")
# five seeds of a synthetic defence evaluation: per-seed attack success rate
rates = []
for seed in range(5):
r = random.Random(seed); rates.append(sum(r.random() < 0.12 for _ in range(200))/200)
m = sum(rates)/5; sd = math.sqrt(sum((x-m)**2 for x in rates)/4)
print("per-seed rates:", " ".join(f"{x:.3f}" for x in rates), f"mean={m:.3f} sd={sd:.3f}")
# paired bootstrap: baseline vs defence on the same 300 synthetic prompts
r = random.Random(42)
base = [r.random() < 0.30 for _ in range(300)]
defn = [b and r.random() < 0.6 for b in base] # defence blocks ~40% of successes
diffs = []
for _ in range(2000):
idx = [r.randrange(300) for _ in range(300)]
diffs.append(sum(base[i] for i in idx)/300 - sum(defn[i] for i in idx)/300)
diffs.sort()
print(f"baseline_asr={sum(base)/300:.3f} defended_asr={sum(defn)/300:.3f} "
f"reduction_ci95=[{diffs[50]:.3f}, {diffs[1949]:.3f}]")
Expected output:
successes=3/20 rate=0.150 wilson95=[0.052, 0.360]
successes=30/200 rate=0.150 wilson95=[0.107, 0.206]
successes=300/2000 rate=0.150 wilson95=[0.135, 0.166]
per-seed rates: 0.110 0.130 0.135 0.105 0.145 mean=0.125 sd=0.017
baseline_asr=0.350 defended_asr=0.190 reduction_ci95=[0.120, 0.203]
6.4 Secondary outcomes and costs
Every security improvement has costs: accuracy, latency, refusals of legitimate requests, compute, maintainability. Report them on the same items. A privacy defence that halves leakage but drops macro-F1 by 10 points is a different proposition from one that costs 1 point. Plot the trade-off (e.g., TPR at 1% FPR versus macro-F1) for all conditions. Leo's result is the second kind: near dedup more than halved TPR at 1% FPR, to 4.2%, while macro-F1 fell by less than one point. Report both numbers together, with intervals, so readers can weigh the trade-off themselves.
6.5 Worked example (synthetic Harbourline case)
Leo's main results (synthetic, five seeds, 20,000 records): TPR at 1% FPR under the calibrated attack was 9.8% (original), 7.9% (random removal), 5.1% (exact dedup) and 4.2% (near dedup). The paired difference between near dedup and random removal was 3.7 points (bootstrap 95% CI 2.6–4.9). Macro-F1 fell from 0.912 to 0.905 under near dedup. Data-quality checks found one missing seed-4 run, rerun and logged. An exploratory analysis, labelled as such, showed leakage concentrated in records that had appeared three or more times. The exploratory finding about records seen three or more times is a hypothesis for future work, not a confirmed result.
6.6 Practice activities
- Write a data-quality checklist for your study and run it. 2. Produce the primary table with intervals. 3. Plot the security–utility trade-off. For the checklist, include all expected runs, canary checks, duplicates across splits and plausible ranges, and run it before any analysis. For the primary table, give each condition's outcome with an interval and the number of seeds. For the plot, put the privacy metric against macro-F1 for every condition, so a reader can see the trade-off at a glance, as Leo's figure does.
6.7 Errors and limits
Four errors recur, and each biases results or hides costs; check your analysis for all four:
- Running all seeds of one condition before another; this lets time-dependent problems, such as a node slowing down, align with that condition.
- Analysing before quality checks; this turns bugs, such as the missing seed-4 run that Leo's checks found, into findings.
- Mixing exploratory and confirmatory results; this overstates certainty.
- Reporting security gains without costs; this hides trade-offs, such as the macro-F1 drop from 0.912 to 0.905 that Leo reported.
Exercises
- EX033 — Interleaving. Why interleave conditions during runs? Rubric: 3 = prevents time-dependent problems confounding conditions; 2 = partial; 1 = vague; 0 = wrong.
- EX034 — Quality checks. List four data-quality checks. Rubric: 3 = completeness, canaries, cross-split duplicates, plausible ranges; 2 = three; 1 = one or two; 0 = none.
- EX035 — Lab reading. What are the baseline and defended ASR and the reduction interval in the stats lab? Rubric: 3 = 0.350, 0.190, [0.120, 0.203]; 2 = two; 1 = one; 0 = wrong.
- EX036 — Paired vs unpaired. Why bootstrap the difference on shared items rather than comparing two separate intervals? Rubric: 3 = item difficulty cancels; tighter, correct inference; 2 = partial; 1 = vague; 0 = wrong.
- EX037 — Costs. Name four costs to report for a security defence. Rubric: 3 = accuracy/utility, latency, false refusals, compute/maintenance; 2 = three; 1 = one or two; 0 = none.
- EX038 — Exploratory. How should Leo report the "three or more appearances" finding? Rubric: 3 = labelled exploratory, hypothesis for future work, not confirmatory; 2 = partial; 1 = reported as main result; 0 = omitted without reason.
Synthesis
Analysis is where careful design pays off: interleaved runs, quality checks, intervals and paired comparisons turn raw logs into a defensible answer, and costs make the answer useful.
Continue studying — chapter 06 of 08
← Chapter 05 (draft) · Course chapter index · Chapter 07 (draft) →