Chapter 5 — Proposal and pilot
Lesson map
Lesson 05 published. Map, example, EX027.
flowchart TD
N0["Learning outcomes"]
N1["5.1 Pilot purpose"]
N2["5.2 The duplicate lab"]
N3["5.3 Correction times"]
N4["5.4 Refining the proposal"]
N5["Lab — Address duplicates before and after normalisat"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5
N5 --> EX["Worked example"]
EX --> Q["Exercise EX027"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["5.1 Pilot purpose"]
N2["5.2 The duplicate lab"]
N3["5.3 Correction times"]
N4["5.4 Refining the proposal"]
N5["Lab — Address duplicates before and after normalisat"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX027"]
[Learning outcomes]
|
v
[5.1 Pilot purpose]
|
v
[5.2 The duplicate lab]
|
v
[5.3 Correction times]
|
v
[5.4 Refining the proposal]
|
v
[Lab — Address duplicates before and after normalisat]
|
v
[Worked example] --> [Exercise EX027]
Learning outcomes
You will (1) pilot measurement of duplicates and correction times; (2) normalise address data; (3) refine the proposal from pilot lessons.
5.1 Pilot purpose
Before the main data collection, Tomás pilots his measurements on a synthetic replica of the address registers. He wants to know whether duplicates can be counted reliably, whether correction times can be extracted from ticket logs and how long each step takes. A pilot is not meant to answer the research question; it tests whether the methods work. Dr. Solberg reminds him that problems found in a pilot are cheap, while the same problems found during the main study can cost months.
5.2 The duplicate lab
The pilot lab builds 3,305 synthetic address records in which a second department sometimes keys the same address with abbreviations, extra spaces and different capitals. Exact matching finds no duplicates at all, because no two strings are identical. After normalisation, which lowercases text, expands abbreviations such as St and Rd and collapses spaces, 384 duplicates appear, 11.6% of records. The result shows that any duplicate measure depends heavily on the normalisation rules chosen, which are themselves a governance decision. The abbreviation rules decide what counts as the same address.
5.3 Correction times
Ticket logs record when an error was reported and when it was closed, but closure does not always mean the address changed in every system. In the replica, some tickets close when the reporting department fixes its own copy while other departments remain wrong. Tomás redefines the outcome as days until the corrected address appears in all five systems, which matches what residents experience. ISO 8000-1's emphasis on requirements helps him justify the change: the requirement is a correct address everywhere, not a closed ticket.
5.4 Refining the proposal
From the pilot, Tomás updates his proposal: duplicate counts will use documented normalisation rules agreed with the stewards, correction time will be measured to the last system updated, and data extraction will take two weeks rather than one. He records the changes and their reasons in his decision log before collecting real outcome data, so the changes cannot be accused of chasing results. Dr. Solberg approves, noting that the pilot has already produced a finding about how definitions shape measured quality.
Lab — Address duplicates before and after normalisation
"""Find duplicate address records before and after normalisation in a synthetic council register (stdlib only)."""
import random, re, collections
random.seed(12)
streets = ["High Street", "Mill Lane", "Church Road", "Station Road", "Park Avenue", "Kings Way"]
base = [(random.randint(1, 120), random.choice(streets), f"AR{random.randint(1,9)} {random.randint(1,9)}QX") for _ in range(3000)]
base = list(dict.fromkeys(base))
recs = []
for n, s, p in base:
recs.append(f"{n} {s}, {p}")
if random.random() < 0.12: # a second department keys the same address differently
v = s.replace("Street", "St").replace("Road", "Rd").replace("Avenue", "Ave")
recs.append(f"{n} {v.upper()},{p.lower()}")
def norm(a):
a = a.lower().replace(",", " ")
for k, v in {" st ": " street ", " rd ": " road ", " ave ": " avenue "}.items():
a = (" " + a + " ").replace(k, v).strip()
return re.sub(r"\s+", " ", a)
exact = len(recs) - len(set(recs))
normd = len(recs) - len({norm(r) for r in recs})
print(f"records {len(recs)}; exact duplicates {exact}; duplicates after normalisation {normd} ({100*normd/len(recs):.1f}%)")
Run with python3 lab_dupes.py. Verified output:
records 3305; exact duplicates 0; duplicates after normalisation 384 (11.6%)
Worked example
Tomás finds no exact duplicates but 384 (11.6%) after normalisation among 3,305 synthetic records, redefines correction time to the last system updated and logs proposal changes before main data collection.
Synthetic case. Records are synthetic; ISO 8000-1:2022 is real.
Errors and limits
Aggressive normalisation can merge different addresses; check a sample by hand.
Exercises
- EX027 — Pilot aim. What is a pilot meant to test? Rubric: 3 = whether the methods work;; 2 = partly correct;; 1 = answer question;; 0 = none.
- EX028 — Exact matches. How many exact duplicates were found? Rubric: 3 = none;; 2 = hedged (few or none);; 1 = wrong;; 0 = no answer.
- EX029 — Normalised duplicates. How many duplicates after normalisation? Rubric: 3 = 384, 11.6%;; 2 = partly correct;; 1 = wrong;; 0 = none.
- EX030 — Normalisation steps. Name two normalisation steps. Rubric: 3 = lowercase, expand abbreviations, collapse spaces;; 2 = two;; 1 = one;; 0 = none.
- EX031 — New outcome. How was correction time redefined? Rubric: 3 = days until correct in all five systems;; 2 = partly correct;; 1 = ticket closure;; 0 = none.
- EX032 — Logged changes. When were proposal changes logged? Rubric: 3 = before collecting real outcome data;; 2 = partly correct;; 1 = after;; 0 = none.
Continue studying — lesson 05 (chapter 05 of 08)
← Chapter 04 · Course chapter index · Chapter 06 →
Continue to the next authored lesson.