Stata Data Cleaning
Generate rigorous, reproducible Stata data-cleaning code that follows DIME Analytics impact-evaluation conventions. The default style is iefolder + iecodebook + ieduplicates + extended missing values + labeled categorical variables — never hand-rolled clear all + cd.
Operating Principles
- Reproducibility first. Every cleaning script starts with
ieboilstart, declares dynamic absolute paths via globals, and runs end-to-end from a clean Stata session. Never cd. Never overwrite raw data. Never commit PII to a public repo.
- Identify and document, then fix. DIME's Data Cleaning guidance is explicit: prioritize identifying and documenting irregularities (outliers, illogical values, typos, duplicates, missing-value codes) before correcting them. Many fixes depend on the analysis design that the PI controls.
- Codebooks, not ad-hoc do-files. Use
iecodebook template and iecodebook apply for repetitive renames/labels/recodes. Codebooks are human-readable, machine-applicable, and easier to review than long do-file blocks.
- Master dataset is the single source of truth. Time-invariant identifying information, sampling, and treatment assignment live in one master dataset per unit of observation. All other datasets link to it.
- Numeric, labeled, and asserted. Categorical variables stored numerically with value labels; survey codes stored as extended missing values (
.a, .b, ..., .z) with labels; every cleaned dataset has isid and assert checks.
Decision Policy
This skill follows the repo-wide Agent Policy. For cross-cutting data discipline (unit of analysis, ID variables, merging, master dataset, PII), this skill defers to working-with-data.
ASK before proceeding (blocking):
- Unit of observation and the unique identifier (single or composite).
- Whether the file contains PII; if yes, is encryption already configured.
- How to resolve duplicates that
ieduplicates finds (correction, update, keep_one, drop).
- Sample restrictions to apply; each
iedropone is logged but the choice is the user's.
- For multi-wave projects: harmonization strategy across rounds (variable name remapping in
iecodebook append).
DEFAULT + flag (use this default; tell the user how to override):
- DataWork folder layout via
iefolder (DIME default).
iecodebook Excel-driven cleaning over hand-written rename/recode/label blocks.
- Extended missing values
.a "Don't know", .b "Refuse", .c "Not applicable", .n "Skipped (logic)" with a single harmonized label set.
encode ..., label() noextend for string categoricals (errors when an unexpected value appears).
ieboilsave before every save; ieboilstart 17.0 at the top of every script.
DOCUMENT and proceed (write into the decisions log + documentation/cleaning_log.md):
- Inferred unit of observation if not stated, with the assertion that confirms it.
- Each filter applied and the resulting N.
- Each value recode and which raw codes mapped where.
- Choice of which extended missing letter maps to which survey code.
PROCEED items: never cd; always reference paths as globals; raw is immutable; encrypted folder gitignored; ieboilsave checks before saving.
Pre-flight Checklist
Before writing code, confirm with the user — and write the answers in the do-file header:
- Data source. Primary survey (CAPI export?), administrative, secondary, or API?
- Unit of observation. Household, individual, firm, plot, school, country-year?
- Unique identifier. Single ID variable (e.g.
hhid)? Composite key (e.g. hhid year)?
- Survey rounds. Single cross-section, panel waves, or repeated cross-sections?
- Sensitive content. Does the raw data contain PII (names, GPS, dates of birth, contact info, photos)?
- Cleaning goals. Recoding, harmonization across waves, de-duplication, missing-value handling, derived variables, or all of the above?
- Output. Analysis-ready
.dta, public-release de-identified .dta, or both?
DIME DataWork Layout
Every cleaning script assumes a DataWork/ folder created by iefolder (see DataWork Folder):
ProjectABC/
├── DataWork/
│ ├── MasterDoFile.do
│ ├── MasterData/ # Time-invariant info, sampling, treatment
│ │ ├── master_household.dta # de-identified
│ │ └── master_household_PII.dta # encrypted-only
│ ├── EncryptedData/ # Anything PII (encrypted with VeraCrypt)
│ │ ├── Baseline/
│ │ └── Endline/
│ └── Baseline/
│ ├── DataSets/
│ │ ├── Raw/ # IMMUTABLE; never edit
│ │ ├── Intermediate/
│ │ └── Final/ # analysis-ready, de-identified
│ ├── Dofiles/
│ │ ├── Cleaning/
│ │ ├── Construction/ # derived variables
│ │ └── Analysis/
│ ├── Output/
│ ├── Documentation/
│ └── Questionnaire/
└── README.md
PII rules (DIME PII page):
- All PII lives in
EncryptedData/, encrypted with VeraCrypt or equivalent.
- The working dataset in
Final/ is de-identified.
- Never commit
EncryptedData/ to git (.gitignore it).
Cleaning Workflow
1. Import raw data (CAPI exporter or read_csv) into Raw/ - IMMUTABLE
2. Validate IDs with ieduplicates / isid
3. Harmonize variables across waves with iecodebook append
4. Apply codebook (iecodebook apply): rename, label, recode, drop
5. Convert survey codes to extended missing values (.a, .b, ...)
6. Convert string categorical to numeric labeled (encode ..., label() noextend)
7. Construct derived variables in a separate construction do-file
8. Validate with assert + isid + duplicates report
9. Save Intermediate -> save Final -> save de-identified version
10. Export iecodebook to Documentation/
Estimator-Free Decision Tree
Duplicates
duplicates report id_var
└── if any:
ieduplicates id_var, ... # creates an Excel report
iecompdup id_var, ... # compare and resolve
Document resolution in Documentation/duplicates_log.xlsx
Missing Values
Survey codes (-99, -88, -77, -98 etc.):
└── Replace with extended missing values:
label define mvlbl .a "Don't know" .b "Refuse" .c "Not applicable"
mvdecode varlist, mv(-99=.a \ -88=.b \ -77=.c)
label values varlist mvlbl
True missingness from survey skip patterns:
└── Use a distinct extended missing value (e.g. .n "Not asked due to skip")
so it is distinguishable from "Don't know".
After cleaning, the Final dataset should contain no plain "." values
in cleaned variables — every missing value should explain itself.
Categorical Variables
Numeric categorical:
label define edu_lbl 1 "None" 2 "Primary" 3 "Secondary" 4 "Tertiary"
label values education edu_lbl
String categorical:
encode region_string, gen(region) label(region_lbl) noextend
// noextend ERRORS if a new value appears that is not in the predefined label
IDs
isid hhid # cross-section
isid hhid year # panel
duplicates report hhid year # any duplicates?
assert !missing(hhid, year) # IDs must be non-missing
Outliers and Illogical Values
1. IDENTIFY before fixing (DIME guidance):
summarize varlist, detail
graph box varlist
scatter varlist xvar
2. Document each anomaly in Documentation/cleaning_log.md
3. Discuss with PI which to flag vs cap vs drop
4. Apply correction in code, never by hand
5. Tag with a flag variable: gen flag_outlier_y = (y > p99 & !mi(y))
Output Skeleton
*-------------------------------------------------------------*
* Project : ProjectABC
* Purpose : Clean baseline household survey
* Author : First Last
* Created : 2026-05-05
* Inputs : ${baseline_raw}/baseline_hh.dta (CAPI export, IMMUTABLE)
* Outputs : ${baseline_int}/baseline_hh_clean.dta
* ${baseline_doc}/baseline_hh_codebook.xlsx
* ${master_data}/master_household.dta
* Estimand : N/A (cleaning, not estimation)
* PII : raw contains names, GPS — handled in EncryptedData/
*-------------------------------------------------------------*
* 0. Settings
ieboilstart, version(17.0)
`r(version)'
* 1. Load raw (NEVER overwrite)
use "${baseline_raw}/baseline_hh.dta", clear
* 2. ID validation
ieduplicates hhid using "${baseline_doc}/duplicates_baseline.xlsx", ///
uniquevars(hhid) keepvars(enum_id submission_date) ///
folder("${baseline_doc}") ///
listofdiffs(diff_log_baseline) replace
isid hhid
* 3. Apply codebook (rename, label, recode in one shot)
iecodebook apply using "${baseline_doc}/baseline_codebook.xlsx", ///
missingvalues(.a "Don't know" .b "Refuse" .c "Not applicable")
* 4. Survey codes to extended missing values
mvdecode age income, mv(-99=.a \ -88=.b \ -77=.c)
mvdecode age income, mv(-98=.n) // .n = "skipped due to logic"
* 5. String to labeled numeric
encode region, gen(region_id) label(region_lbl) noextend
* 6. Validation
assert age >= 0 & age <= 120 if !missing(age)
assert inlist(female, 0, 1) if !missing(female)
isid hhid
* 7. Save (with checks)
ieboilsave, ///
idvars(hhid) ///
versionvar(version_var) // adds version comment
save "${baseline_int}/baseline_hh_clean.dta", replace
* 8. Export codebook for documentation
iecodebook export using "${baseline_doc}/baseline_hh_codebook.xlsx", replace
Common Pitfalls
- Hardcoded paths and
cd — break collaboration; use globals defined in MasterDoFile.do.
- Editing raw data —
Raw/ is immutable; create Intermediate/ outputs.
- Plain
. for everything missing — kills downstream interpretation; use extended missing values with labels.
encode without label() noextend — silently rebases codes when new values appear; always pre-define the label.
- Dropping rows without
iedropone — silent drops break replication; iedropone errors if the count is unexpected.
- Committing
EncryptedData/ or files containing names, GPS, contact info to git.
- Long ad-hoc rename/label/recode blocks — replace with
iecodebook apply driven by an Excel codebook.
- Saving over the master dataset from a cleaning script — master is updated through a controlled process.
Additional Resources
reference.md — extended code patterns, codebook recipes, harmonization, and master-dataset workflow.
examples/ — runnable do-files:
examples/master_cleaning.do — entry point that routes to all cleaning steps
examples/clean_with_iecodebook.do — codebook-driven cleaning
examples/duplicates_workflow.do — ieduplicates + iecompdup
examples/missing_values_extended.do — extended missing values for survey codes
examples/harmonize_waves_iecodebook.do — iecodebook append across rounds
examples/master_dataset.do — building and updating a master dataset
examples/deidentify_for_release.do — strip PII for public release
Requirements
- Stata >= 16.
- DIME packages:
iefieldkit (provides iecodebook, ieduplicates, iecompdup, ietestform), ietoolkit (provides iefolder, ieboilstart, ieboilsave, iedropone).
- Optional helpers:
mdesc, unique, labutil, fre, winsor2, quantiles (for cross-checks).
ssc install iefieldkit, replace
ssc install ietoolkit, replace
ssc install mdesc, replace
ssc install unique, replace
ssc install labutil, replace
ssc install fre, replace
ssc install winsor2, replace
References
DIME Conventions
Style References
- Gentzkow & Shapiro (2014). Code and Data for the Social Sciences.
- IPA, Reproducible Research: Best Practices for Data and Code Management.
1---2name: stata-data-cleaning3description: Generates rigorous, reproducible Stata data-cleaning workflows that follow World Bank DIME Analytics conventions (`iefieldkit`, `ietoolkit`, `iefolder` DataWork structure, `ieboilstart`, `iecodebook`, `ieduplicates`, `iecompdup`, extended missing values, master datasets, encryption for PII, dynamic absolute paths). Defaults to codebook-driven cleaning, `assert`/`isid` validation, labeled categorical variables, and reproducible from-clean-session execution. Use when the user asks to clean survey or administrative data in Stata, build an analysis-ready panel, handle duplicates, harmonize datasets across rounds, write a master dataset, de-identify data, label variables, or produce a codebook.4---56# Stata Data Cleaning78Generate rigorous, reproducible Stata data-cleaning code that follows DIME Analytics impact-evaluation conventions. The default style is `iefolder` + `iecodebook` + `ieduplicates` + extended missing values + labeled categorical variables — never hand-rolled `clear all` + `cd`.910## Operating Principles11121. **Reproducibility first.** Every cleaning script starts with `ieboilstart`, declares dynamic absolute paths via globals, and runs end-to-end from a clean Stata session. Never `cd`. Never overwrite raw data. Never commit PII to a public repo.132. **Identify and document, then fix.** DIME's [Data Cleaning](https://dimewiki.worldbank.org/Data_Cleaning) guidance is explicit: prioritize identifying and documenting irregularities (outliers, illogical values, typos, duplicates, missing-value codes) before correcting them. Many fixes depend on the analysis design that the PI controls.143. **Codebooks, not ad-hoc do-files.** Use `iecodebook template` and `iecodebook apply` for repetitive renames/labels/recodes. Codebooks are human-readable, machine-applicable, and easier to review than long do-file blocks.154. **Master dataset is the single source of truth.** Time-invariant identifying information, sampling, and treatment assignment live in one master dataset per unit of observation. All other datasets link to it.165. **Numeric, labeled, and asserted.** Categorical variables stored numerically with value labels; survey codes stored as extended missing values (`.a`, `.b`, ..., `.z`) with labels; every cleaned dataset has `isid` and `assert` checks.1718## Decision Policy1920This skill follows the repo-wide [Agent Policy](../../AGENT_POLICY.md). For cross-cutting data discipline (unit of analysis, ID variables, merging, master dataset, PII), this skill defers to [`working-with-data`](../working-with-data/).2122**ASK before proceeding** (blocking):23241. Unit of observation and the unique identifier (single or composite).252. Whether the file contains PII; if yes, is encryption already configured.263. How to resolve duplicates that `ieduplicates` finds (correction, update, keep_one, drop).274. Sample restrictions to apply; each `iedropone` is logged but the choice is the user's.285. For multi-wave projects: harmonization strategy across rounds (variable name remapping in `iecodebook append`).2930**DEFAULT + flag** (use this default; tell the user how to override):3132- DataWork folder layout via `iefolder` (DIME default).33- `iecodebook` Excel-driven cleaning over hand-written rename/recode/label blocks.34- Extended missing values `.a` "Don't know", `.b` "Refuse", `.c` "Not applicable", `.n` "Skipped (logic)" with a single harmonized label set.35- `encode ..., label() noextend` for string categoricals (errors when an unexpected value appears).36- `ieboilsave` before every save; `ieboilstart 17.0` at the top of every script.3738**DOCUMENT and proceed** (write into the decisions log + `documentation/cleaning_log.md`):3940- Inferred unit of observation if not stated, with the assertion that confirms it.41- Each filter applied and the resulting N.42- Each value recode and which raw codes mapped where.43- Choice of which extended missing letter maps to which survey code.4445`PROCEED` items: never `cd`; always reference paths as globals; raw is immutable; encrypted folder gitignored; `ieboilsave` checks before saving.4647## Pre-flight Checklist4849Before writing code, confirm with the user — and write the answers in the do-file header:5051- **Data source.** Primary survey (CAPI export?), administrative, secondary, or API?52- **Unit of observation.** Household, individual, firm, plot, school, country-year?53- **Unique identifier.** Single ID variable (e.g. `hhid`)? Composite key (e.g. `hhid year`)?54- **Survey rounds.** Single cross-section, panel waves, or repeated cross-sections?55- **Sensitive content.** Does the raw data contain PII (names, GPS, dates of birth, contact info, photos)?56- **Cleaning goals.** Recoding, harmonization across waves, de-duplication, missing-value handling, derived variables, or all of the above?57- **Output.** Analysis-ready `.dta`, public-release de-identified `.dta`, or both?5859## DIME DataWork Layout6061Every cleaning script assumes a `DataWork/` folder created by `iefolder` (see [DataWork Folder](https://dimewiki.worldbank.org/DataWork_Folder)):6263```64ProjectABC/65├── DataWork/66│ ├── MasterDoFile.do67│ ├── MasterData/ # Time-invariant info, sampling, treatment68│ │ ├── master_household.dta # de-identified69│ │ └── master_household_PII.dta # encrypted-only70│ ├── EncryptedData/ # Anything PII (encrypted with VeraCrypt)71│ │ ├── Baseline/72│ │ └── Endline/73│ └── Baseline/74│ ├── DataSets/75│ │ ├── Raw/ # IMMUTABLE; never edit76│ │ ├── Intermediate/77│ │ └── Final/ # analysis-ready, de-identified78│ ├── Dofiles/79│ │ ├── Cleaning/80│ │ ├── Construction/ # derived variables81│ │ └── Analysis/82│ ├── Output/83│ ├── Documentation/84│ └── Questionnaire/85└── README.md86```8788PII rules ([DIME PII page](https://dimewiki.worldbank.org/Personally_Identifiable_Information_(PII))):8990- All PII lives in `EncryptedData/`, encrypted with VeraCrypt or equivalent.91- The working dataset in `Final/` is de-identified.92- Never commit `EncryptedData/` to git (`.gitignore` it).9394## Cleaning Workflow9596```971. Import raw data (CAPI exporter or read_csv) into Raw/ - IMMUTABLE982. Validate IDs with ieduplicates / isid993. Harmonize variables across waves with iecodebook append1004. Apply codebook (iecodebook apply): rename, label, recode, drop1015. Convert survey codes to extended missing values (.a, .b, ...)1026. Convert string categorical to numeric labeled (encode ..., label() noextend)1037. Construct derived variables in a separate construction do-file1048. Validate with assert + isid + duplicates report1059. Save Intermediate -> save Final -> save de-identified version10610. Export iecodebook to Documentation/107```108109## Estimator-Free Decision Tree110111### Duplicates112113```114duplicates report id_var115 └── if any:116 ieduplicates id_var, ... # creates an Excel report117 iecompdup id_var, ... # compare and resolve118 Document resolution in Documentation/duplicates_log.xlsx119```120121### Missing Values122123```124Survey codes (-99, -88, -77, -98 etc.):125 └── Replace with extended missing values:126 label define mvlbl .a "Don't know" .b "Refuse" .c "Not applicable"127 mvdecode varlist, mv(-99=.a \ -88=.b \ -77=.c)128 label values varlist mvlbl129130True missingness from survey skip patterns:131 └── Use a distinct extended missing value (e.g. .n "Not asked due to skip")132 so it is distinguishable from "Don't know".133134After cleaning, the Final dataset should contain no plain "." values135in cleaned variables — every missing value should explain itself.136```137138### Categorical Variables139140```141Numeric categorical:142 label define edu_lbl 1 "None" 2 "Primary" 3 "Secondary" 4 "Tertiary"143 label values education edu_lbl144145String categorical:146 encode region_string, gen(region) label(region_lbl) noextend147 // noextend ERRORS if a new value appears that is not in the predefined label148```149150### IDs151152```153isid hhid # cross-section154isid hhid year # panel155duplicates report hhid year # any duplicates?156assert !missing(hhid, year) # IDs must be non-missing157```158159### Outliers and Illogical Values160161```1621. IDENTIFY before fixing (DIME guidance):163 summarize varlist, detail164 graph box varlist165 scatter varlist xvar1662. Document each anomaly in Documentation/cleaning_log.md1673. Discuss with PI which to flag vs cap vs drop1684. Apply correction in code, never by hand1695. Tag with a flag variable: gen flag_outlier_y = (y > p99 & !mi(y))170```171172## Output Skeleton173174```stata175*-------------------------------------------------------------*176* Project : ProjectABC177* Purpose : Clean baseline household survey178* Author : First Last179* Created : 2026-05-05180* Inputs : ${baseline_raw}/baseline_hh.dta (CAPI export, IMMUTABLE)181* Outputs : ${baseline_int}/baseline_hh_clean.dta182* ${baseline_doc}/baseline_hh_codebook.xlsx183* ${master_data}/master_household.dta184* Estimand : N/A (cleaning, not estimation)185* PII : raw contains names, GPS — handled in EncryptedData/186*-------------------------------------------------------------*187188* 0. Settings189ieboilstart, version(17.0)190`r(version)'191192* 1. Load raw (NEVER overwrite)193use "${baseline_raw}/baseline_hh.dta", clear194195* 2. ID validation196ieduplicates hhid using "${baseline_doc}/duplicates_baseline.xlsx", ///197 uniquevars(hhid) keepvars(enum_id submission_date) ///198 folder("${baseline_doc}") ///199 listofdiffs(diff_log_baseline) replace200201isid hhid202203* 3. Apply codebook (rename, label, recode in one shot)204iecodebook apply using "${baseline_doc}/baseline_codebook.xlsx", ///205 missingvalues(.a "Don't know" .b "Refuse" .c "Not applicable")206207* 4. Survey codes to extended missing values208mvdecode age income, mv(-99=.a \ -88=.b \ -77=.c)209mvdecode age income, mv(-98=.n) // .n = "skipped due to logic"210211* 5. String to labeled numeric212encode region, gen(region_id) label(region_lbl) noextend213214* 6. Validation215assert age >= 0 & age <= 120 if !missing(age)216assert inlist(female, 0, 1) if !missing(female)217isid hhid218219* 7. Save (with checks)220ieboilsave, ///221 idvars(hhid) ///222 versionvar(version_var) // adds version comment223save "${baseline_int}/baseline_hh_clean.dta", replace224225* 8. Export codebook for documentation226iecodebook export using "${baseline_doc}/baseline_hh_codebook.xlsx", replace227```228229## Common Pitfalls230231- Hardcoded paths and `cd` — break collaboration; use globals defined in `MasterDoFile.do`.232- Editing raw data — `Raw/` is immutable; create `Intermediate/` outputs.233- Plain `.` for everything missing — kills downstream interpretation; use extended missing values with labels.234- `encode` without `label() noextend` — silently rebases codes when new values appear; always pre-define the label.235- Dropping rows without `iedropone` — silent drops break replication; `iedropone` errors if the count is unexpected.236- Committing `EncryptedData/` or files containing names, GPS, contact info to git.237- Long ad-hoc rename/label/recode blocks — replace with `iecodebook apply` driven by an Excel codebook.238- Saving over the master dataset from a cleaning script — master is updated through a controlled process.239240## Additional Resources241242- `reference.md` — extended code patterns, codebook recipes, harmonization, and master-dataset workflow.243- `examples/` — runnable do-files:244 - `examples/master_cleaning.do` — entry point that routes to all cleaning steps245 - `examples/clean_with_iecodebook.do` — codebook-driven cleaning246 - `examples/duplicates_workflow.do` — `ieduplicates` + `iecompdup`247 - `examples/missing_values_extended.do` — extended missing values for survey codes248 - `examples/harmonize_waves_iecodebook.do` — `iecodebook append` across rounds249 - `examples/master_dataset.do` — building and updating a master dataset250 - `examples/deidentify_for_release.do` — strip PII for public release251252## Requirements253254- Stata >= 16.255- DIME packages: `iefieldkit` (provides `iecodebook`, `ieduplicates`, `iecompdup`, `ietestform`), `ietoolkit` (provides `iefolder`, `ieboilstart`, `ieboilsave`, `iedropone`).256- Optional helpers: `mdesc`, `unique`, `labutil`, `fre`, `winsor2`, `quantiles` (for cross-checks).257258```stata259ssc install iefieldkit, replace260ssc install ietoolkit, replace261ssc install mdesc, replace262ssc install unique, replace263ssc install labutil, replace264ssc install fre, replace265ssc install winsor2, replace266```267268## References269270### DIME Conventions271272- DIME Analytics, [Data Cleaning](https://dimewiki.worldbank.org/Data_Cleaning)273- DIME Analytics, [DataWork Folder](https://dimewiki.worldbank.org/DataWork_Folder)274- DIME Analytics, [Master Do-files](https://dimewiki.worldbank.org/Master_Do-files)275- DIME Analytics, [iecodebook](https://dimewiki.worldbank.org/Iecodebook)276- DIME Analytics, [ietoolkit](https://dimewiki.worldbank.org/ietoolkit)277- DIME Analytics, [iefieldkit](https://dimewiki.worldbank.org/Iefieldkit)278- DIME Analytics, [Personally Identifiable Information (PII)](https://dimewiki.worldbank.org/Personally_Identifiable_Information_(PII))279- DIME Analytics, [ID Variable Properties](https://dimewiki.worldbank.org/ID_Variable_Properties)280- DIME Analytics, [Reproducible Research](https://dimewiki.worldbank.org/Reproducible_Research)281- *Development Research in Practice* (DIME Analytics handbook).282283### Style References284285- Gentzkow & Shapiro (2014). *Code and Data for the Social Sciences*.286- IPA, *Reproducible Research: Best Practices for Data and Code Management*.