Skip to content
Synthetic population
Data · release 1.0.3

Can I use these data?

The full microdata are published under the CC BY-NC 4.0 licence. This page says what they contain, what they are and are not for, how to verify the files and how to cite them.

pt-synthpop-v1.0.3.zip · 181.7 MB · GitHub

Which release is this?

Release
pt-synthpop 1.0.3, dated 5 October 2026 (published on GitHub on 6 October 2026)
Reference year
2021: generated from INE’s 2021 Census.
Model
Engine v10, a single run. sha256 062e2ad784886b7287536233f853db151c57615d2b1a952fb2e12368581e76d3
Code
Commit 4bf0819 of the packaging code; the repository is not public yet.
Previous releases
1.0.3 replaced three releases dated 5 October (1.0.2 never reached GitHub); the generated population is the same in all of them.
What changed between releases

Release 1.0.3 replaced releases 1.0.0, 1.0.1 and 1.0.2, all of 5 October 2026. Release 1.0.0 applied launch thresholds to the site’s answers that hid about half of the parish answers; 1.0.1 removed them, so every parish answers with its own figures; 1.0.2 asked the household questions of private households and fixed the presentation; 1.0.3 corrected the microdata’s nuts2 column to the 2013 NUTS II regions. The generated people and households are the same in all four releases. The files of releases 1.0.0 and 1.0.1 stay on GitHub, as a record, in the list of releases; 1.0.2 was never published there.

May I use and share them?

Yes, for non-commercial purposes. estimador.pt publishes the synthetic population under the CC BY-NC 4.0 licence: you may use, adapt and redistribute it for non-commercial purposes, as long as you include the attribution given below. The licence does not cover commercial use. The INE data it is based on (the 2021 Census published tables and Public Use File) are reused under INE’s CC BY 4.0 licence. They are not official INE microdata.

Suitable for…

  • Descriptive demographic exploration.
  • Small-area household and population analysis within the published quality rules.
  • Journalism and civic-data applications.
  • Education and reproducible research.
  • Aggregate scenario and poststratification work (reweighting a survey so it matches the population). This release publishes no uncertainty (a single run): treat the figures as point values.
  • Testing tools that require realistic but non-identifying population records.

Not suitable for…

  • Identifying, locating, or making decisions about real people.
  • Treating a synthetic row as an individual, family, or address.
  • Unrestricted cross-tabulation in tiny or weak-quality parishes.
  • Parish-level claims based on fields that are not fitted per parish: industry, occupation, place of work, means of transport, tenure and number of rooms (the column dictionary says which they are).
  • Causal conclusions about policy effects.
  • Behavioural prediction or agent-based simulation without a separate validated model.
  • Replacing official Census statistics.
  • Legal, credit, insurance, employment, policing, or eligibility decisions.

If, after reading this page, you conclude that these data do not suit your study, the visit was still worth it: better to know now than after drawing conclusions.

What is each row?

Generated people and households, not real people, families, or addresses.

Persons
10,340,441 rows, one per generated person, including residents of collective quarters (is_institutional = 1, partial records).
Households
4,154,571 rows, one per generated household. Each collective living quarter counts as one household (is_institutional = 1). The site’s household questions count private households only (is_institutional = 0).
Join
Persons and households join on (freguesia, synthetic_hh_id): the household id is unique only within a parish.

What geography does it cover?

Parishes
3,092 parishes published, none suppressed for size. Small ones carry a quality tier instead of being withheld.
Codes
6-character DICOFRE codes from CAOP 2021 (the 2021 Census parishes). Eight Barcelos codes contain letters (0302FA to 0302FH): read the column as text, not as a number. Join tables on the code (municipio), never on the name: the package’s names come from INE’s 2021 Census geography (for example “Calheta (R.A.M.)” and “Lagoa (R.A.A.)”) and differ from the site’s (CAOP 2021), where two municipalities are called Lagoa.
After 2025
Since the October 2025 local elections (Law 25-A/2025), 135 parish unions have been split into 302 parishes. This release uses the 2021 parishes: to join later data (the 2025 local election results, CAOP 2024 or 2025) you need a correspondence table between the 2021 codes and the current ones.
Regions
The nuts2 column is the parish’s NUTS II (2013) region. Up to release 1.0.2 it was a district grouping; 1.0.3 corrected it (see the errata).
Municipalities
308 municipalities, coded as DDCC00.
Partitioning
In the package the microdata are partitioned by district (the first two digits of the parish code), with a consolidated national copy.

Where do I download them?

The files are in a release published on GitHub, in a public data repository.

Release files
File and contentsSize
pt-synthpop-v1.0.3.zipFull package: district and national microdata, quality, metadata, documentation and checksums.181.7 MB
pt-synthpop-v1.0.3-persons.parquetPersons, national file (Parquet).78.2 MB
pt-synthpop-v1.0.3-households.parquetHouseholds, national file (Parquet).6.8 MB
pt-synthpop-v1.0.3-quality.csvQuality: one row per parish (CSV).668 kB
pt-synthpop-v1.0.3-metadata.jsonMetadata: column dictionary, code label maps and provenance (JSON).67 kB
checksums.sha256SHA-256 sums of every file in the package.7 kB
SHA256SUMSSHA-256 sums of the files published with the release.573 B

First steps

Three examples that join persons to households; the last one reproduces a card on the site. As in the site’s household questions, they keep private households only (is_institutional = 0). If you publish tables made from these data, follow the site’s rules: state each parish’s quality tier, read categories with few people and tier C parishes with more care, and make no rankings or “more than” comparisons from a single run.

-- DuckDB: persons by household size, in one parish
SELECT h.hh_size_bin, count(*) AS persons
FROM 'pt-synthpop-v1.0.3-persons.parquet' AS p
JOIN 'pt-synthpop-v1.0.3-households.parquet' AS h
  USING (freguesia, synthetic_hh_id)
WHERE p.freguesia = '060318'
  -- private households only, as on the site: collective quarters
  -- (is_institutional = 1) count as one household and almost all fall under "5"
  AND h.is_institutional = 0
GROUP BY h.hh_size_bin
ORDER BY h.hh_size_bin;
# Python (pandas + pyarrow)
import pandas as pd

persons = pd.read_parquet("pt-synthpop-v1.0.3-persons.parquet")
households = pd.read_parquet("pt-synthpop-v1.0.3-households.parquet")

# synthetic_hh_id is unique only within a parish
merged = persons.merge(
    households, on=["freguesia", "synthetic_hh_id"], suffixes=("", "_hh")
)

# private households only, as on the site (collective quarters have is_institutional = 1)
private = merged[merged["is_institutional_hh"] == 0]
-- DuckDB: reproduces a card on the site, “How many people aged 65 or over live alone?”
-- in Moreira de Cónegos (030831); it should return 0.149, the page’s 14.9%
SELECT avg(CASE WHEN h.hh_size = 1 THEN 1 ELSE 0 END) AS living_alone
FROM 'pt-synthpop-v1.0.3-persons.parquet' AS p
JOIN 'pt-synthpop-v1.0.3-households.parquet' AS h
  USING (freguesia, synthetic_hh_id)
WHERE p.freguesia = '030831'
  AND p.age >= 65
  AND h.is_institutional = 0;

What columns does it have?

The metadata file’s column dictionary, as it stands there, with two differences. In 17 columns, marked “wording revised by the site”, the description was rewritten: it either pointed to the producer’s internal documents or said the opposite of the model card and the data (for example, that industry and occupation are fitted per parish, when they are not); where the two differ, the site’s holds, and the original text stays in the file. And three code columns (activity sector, five-level education and nuts2) have no map in label_maps: the site gives it here. The other labels are in that same file, under label_maps.

Where each column comes from

G
Generated. Produced by the model. It may or may not be fitted to an INE parish table; the column’s description says which.
D
Derived. Computed from another column by a fixed rule (a grouping, a label). As reliable as its parent column.
C
Consistency-enforced. Recomputed after generation to agree with the rest of the record; for example, household size is the number of its persons.
X
Geographic. Assigned from the parish code (CAOP 2021). An identifier, not a model output.
key
Key. Links persons to households.
flag
Flag. A 0/1 indicator.
Persons · 33 columns
activity_sector_codeprovenance D
Activity sector in four groups (1–4); employed only. Derived from the generated activity; the activity-sector table is one of the tables the population was fitted to.(wording revised by the site)Labels (from the site; the file does not carry them yet): 1 Primary sector (CAE A) · 2 Secondary sector (CAE B to F) · 3 Social tertiary (CAE O to U, without division 95) · 4 Economic tertiary (CAE G to N, and division 95)
ageprovenance G
Age in completed years, generated as a single year; for residents of collective quarters, drawn inside the published 5-year band.(wording revised by the site)
age_12grpprovenance D
Age band of INE 12868 (marital universe); null under 12.
age_15grpprovenance D
Age band of INE 12364/12880 ('Menos de 15 anos', ...).
age_5yprovenance D
5-year band of age; '90 ou mais anos' tops it.
age_groupprovenance D
‘0 - 14 anos’ if age < 15, else ‘15 e mais anos’, derived from age.(wording revised by the site)
age_union7provenance D
Age band of INE 12375 (union universe); null under 15.
districtprovenance X
2-digit district code; the Hive partition key (path only in shards).
education_levelprovenance D
Portuguese label of education_level_code, regenerated from the code.
education_level_coarse5provenance D
Education in 5 levels, from the leaf code.Labels (from the site; the file does not carry them yet): 1 None · 2 Basic education (1st to 3rd cycle) · 3 Upper secondary · 4 Post-secondary · 5 Tertiary
education_level_codeprovenance G
Highest completed education, 11 leaf codes (INE 12459).Labels: label_maps.education_level_code
employment_statusprovenance D
Portuguese label of employment_status_code, regenerated from the code.
employment_status_coarse3provenance D
11 employed, 12 unemployed, 2 inactive (from the leaf code).
employment_status_codeprovenance G
Condition towards work, 7 leaf codes (INE 12460).Labels: label_maps.employment_status_code
freguesiaprovenance X
6-character DICOFRE parish code of residence (CAOP 2021). Eight Barcelos codes contain letters (0302FA to 0302FH): read the column as text.(wording revised by the site)
freguesia_nameprovenance X
Name of freguesia (CAOP lookup).
income_source_codeprovenance G
Main source of livelihood (MEIOVIDA); null under 15.Labels: label_maps.income_source_code
industry_sectionprovenance G
CAE Rev. 3 section of the activity, A..U with S split into S_94_96 / S_95; employed only. Generated, and compared with INE’s per-parish employed × sex × industry table when scoring; not fitted to it (see the quality page).(wording revised by the site)Labels: label_maps.industry_section
is_institutionalprovenance flag
1 = resident of a collective living quarter, appended after the fit: sex and age from INE’s published counts, education imputed from similar records; employment status, marital status, nationality, religion and income source filled (null below the same ages as for everyone else). Null for every such resident: nucleus_id and the work columns sitprof_code, activity_sector_code, occupation_major, occupation_code, industry_section, work_location_type and transport_mode.(wording revised by the site)
marital_status_codeprovenance G
Legal marital status (ESTCIVIL); null under 12.Labels: label_maps.marital_status_code
municipioprovenance X
6-digit município code (DDCC00).
municipio_nameprovenance X
Municipality name from INE’s 2021 Census geography (e.g. ‘Calheta (R.A.M.)’, ‘Lagoa (R.A.A.)’), CAOP 2024.1 where INE has none. The site shows CAOP 2021 names: join on municipio, not on the name.(wording revised by the site)
nationality_groupprovenance G
PT / Foreign (binary; no country).
nucleus_idprovenance G
Family-nucleus membership inside the household: ‘0’ = in no nucleus, ‘1’..‘5’ = the person’s nucleus (a label, numbered by first appearance in age-descending member order; not a rank). Null for every resident of a collective living quarter (is_institutional = 1): read null as “no household nucleus recorded”, not as ‘0’. Known defect: INE’s nucleus has at least two members, and some generated nuclei have one. It does not identify couples: the release carries no partner link.(wording revised by the site)
occupation_codeprovenance D
CPP 2010 3-digit minor group; employed only. Derived inside the generated occupation_major from INE table 12306’s per-parish × sex shares (else the município’s, else the national ones), so it rolls up to occupation_major exactly.(wording revised by the site)Labels: label_maps.occupation_code
occupation_majorprovenance G
CPP 2010 major group (first digit of occupation_code); employed only. Generated, and compared with INE’s per-parish employed × sex × occupation table when scoring; not fitted to it (see the quality page).(wording revised by the site)
religion_groupprovenance G
Religion group, 15+ universe.
sexprovenance G
H = Homem (male), M = Mulher (female). M is FEMALE.
sitprof_codeprovenance G
Status in employment (SITPROF); employed only.Labels: label_maps.sitprof_code
synthetic_hh_idprovenance key
The person's household: join on (freguesia, synthetic_hh_id).
transport_modeprovenance G
Main means of transport to work or study (INE 12371 Dim5, '01'..'11'), or NR = travels, mode not reported; only for work_location_type 2-5. Generated.Labels: label_maps.transport_mode
union_de_factoprovenance G
Lives in a de-facto union: Yes / No.
work_location_typeprovenance G
Place of work or study (INE 12369 Dim5): 1 at home, 2 this parish, 3 another parish of the município, 4 another município, 5 abroad, 6 no fixed place; employed and students only. Generated.Labels: label_maps.work_location_type
Households · 17 columns
accessibility_codeprovenance G
Dwelling accessible to a wheelchair user (Census PUF ACESSO): 1 yes, 2 no. Bound per parish to INE’s dwelling-accessibility table (BGRI) and scored. Null where hh_tenure_code is.(wording revised by the site)Labels: label_maps.accessibility_code
districtprovenance X
2-digit district code (first two digits of freguesia). The Hive partition key: in the partitioned shards it is in the path only.
freguesiaprovenance X
6-character DICOFRE parish code of residence (CAOP 2021). Eight Barcelos codes contain letters (0302FA to 0302FH): read the column as text.(wording revised by the site)
freguesia_nameprovenance X
Name of freguesia (CAOP lookup).
hh_rooms_binprovenance D
n_divisions at the grain INE publishes per parish: 1_2, 3_4, 5+.(wording revised by the site)Labels: label_maps.hh_rooms_bin
hh_sizeprovenance G/C
Number of residents (= the household's person rows).
hh_size_binprovenance D
hh_size top-coded at 5 ('5' = 5 or more).
hh_tenure_codeprovenance G
Tenure (regime de ocupação) in INE table 12498’s vocabulary: 1 owner or co-owner, 3 tenant or sub-tenant, 4 other (a one-to-one recode of the Census PUF’s COND_OCUP). Null outside habitual classical dwellings (a small share of private households) and for collective living quarters. Published but not fitted per parish: villages overstate renters.(wording revised by the site)Labels: label_maps.hh_tenure_code
hh_type_topprovenance D
Household type by number of family nuclei: 1 none, 2 one, 3 two, 4 three or more. Derived from n_nuclei when the release is packaged, so a household and its persons always agree. Null for collective living quarters.(wording revised by the site)Note from the site: the answer “What families do they form?” was computed before the microdata’s final packaging and may differ slightly from what this column gives; the producer will correct it.Labels: label_maps.hh_type_top
is_institutionalprovenance flag
1 = a collective-dwelling container for the institutional residents appended after the fit from INE's published counts; 0 = a private household.
municipioprovenance X
6-digit município code (DDCC00).
municipio_nameprovenance X
Municipality name from INE’s 2021 Census geography (e.g. ‘Calheta (R.A.M.)’, ‘Lagoa (R.A.A.)’), CAOP 2024.1 where INE has none. The site shows CAOP 2021 names: join on municipio, not on the name.(wording revised by the site)
n_divisionsprovenance G
Rooms (divisões) of the dwelling, ‘1’..‘10’ where ‘10’ = 10 or more. Same universe and null set as hh_tenure_code. Not fitted per parish.(wording revised by the site)
n_nucleiprovenance D
Number of distinct family nuclei (INE núcleo familiar) among the household's own persons, counted from nucleus_id at packaging. Null for institutional containers.
nuts2provenance X
NUTS II (2013) region code of residence.Labels (from the site; the file does not carry them yet): 11 Norte · 15 Algarve · 16 Centro · 17 Lisbon Metropolitan Area · 18 Alentejo · 20 Autonomous Region of the Azores · 30 Autonomous Region of Madeira
residents_per_roomprovenance D
hh_size / n_divisions (with '10' read as 10). Null where n_divisions is.
synthetic_hh_idprovenance key
Household id, unique only within a parish: join persons on (freguesia, synthetic_hh_id).

How good are each parish’s data?

The quality file has one row per parish, with its publication population and its tier. Read it before using a single parish on its own: below 500 residents none reaches tier A or B.

  • Quality A776 parishes
  • Quality B705 parishes
  • Quality C1,611 parishes

What each column of the quality file says

The quality.csv file, which the package README says to read first. Source: INE (a published count), generated (counted in the generated population), evaluation (measured against INE’s tables) or geographic.

freguesiaGeographic
Parish DICOFRE code (6 characters, CAOP 2021). Read it as text.
freguesia_nameGeographic
Parish name, in capitals.
municipio, municipio_nameGeographic
Municipality code (DDCC00) and INE’s (2021) name.
district, nuts2Geographic
District (2 digits) and 2013 NUTS II region (corrected in 1.0.3).
populationGenerated
People generated in the parish, residents of collective quarters included. Summed, they give the release’s persons.
census_populationINE
Residents according to INE (the total of the 2021 Census sex × age table). It is the count the site shows as “residents (INE)”.
publication_populationEvaluation
The smaller of the two counts above: it decides the tiers’ 500 and 2,000-resident thresholds. population and census_population do not agree in every parish (the generated population does not reproduce INE’s total exactly; the figures are under the table); the package does not record the reason parish by parish.
n_householdsGenerated
Generated households, counting each collective living quarter as one. It is not INE’s count of private households.
n_institutional_personsGenerated
People in collective living quarters, appended from INE’s counts.
pct_children_u15Generated
Share (from 0 to 1) of generated people under 15.
quality_tierEvaluation
Quality tier: A, B or C.
person_srmse_medianEvaluation
The parish’s typical error: the median of the 12 errors (SRMSE) of the fitted person tables, one per table (0 would match the tables). It is the tiers’ first criterion. It is not the “fit error” in the quality page’s chart by size, which pools all the cells of the 12 tables: the two give different medians per band.
worst_constraint, worst_constraint_srmseEvaluation
The person table with the largest error, and that error (the tiers’ second criterion), single-year age included. In most parishes it is single-year age (srmse_p_age_single). Which table each code is: under the table.
suppression_reasonRelease
Empty for every parish: none is suppressed.
fallback_geographyRelease
For tier C parishes, the municipality code, for readers who prefer to aggregate to it. The site does not use it: every parish answers with its own figures.
engine, model_version, run_dateRelease
The engine, the model version and the run date.

The generated total is not always INE’s: in 762 parishes it differs, from 119 people fewer to 30 more; nationally, there are 2,625 people fewer (10,340,441 generated, against 10,343,066 residents according to INE). The quality tiers use the smaller of the two counts, the publication count.

Which table each worst_constraint code is
srmse_p_age5
Age (5-year bands)
srmse_p_marital
Marital status
srmse_p_educ
Education
srmse_p_labour
Labour-force status
srmse_p_income
Main source of livelihood
srmse_p_labour3_educ5
Labour × education
srmse_p_labour3_income
Labour × source of livelihood
srmse_p_nat
Nationality
srmse_p_religion
Religion
srmse_p_sitprof
Status in employment
srmse_p_sector
Activity sector (four groups)
srmse_p_union
De facto union
srmse_p_age_single
Single-year age

How do we know it works?

How do I verify the files?

The SHA-256 of the package’s list of sums (checksums.sha256) is 0992bcfec9595df4fc2102349a6692e570ebc4322377e85438d795dc5a4ab8d8. If it matches, every file in the package can be checked against that list.

# 1. The downloaded files, against SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing

# 2. The package contents, in the folder holding checksums.sha256
sha256sum -c checksums.sha256

# 3. The list of sums is the published one: it should print
# 0992bcfec9595df4fc2102349a6692e570ebc4322377e85438d795dc5a4ab8d8
sha256sum checksums.sha256

On macOS, use shasum -a 256 instead of sha256sum.

How do I cite them?

The CC BY-NC 4.0 licence asks for attribution in any use. When you redistribute the data (the files, or tables taken from them), include the full attribution below. In a news story, a chart or a card, the short form is enough, with a link to this page:

Source: INE, 2021 Census (CC BY 4.0) · information modified by estimador.pt (CC BY-NC 4.0)

Attribution in English

Source: Instituto Nacional de Estatística, IP – Portugal (2021 Population and Housing Census; reference period: 2021). Modified information: this is a synthetic population produced by estimador.pt from the Census 2021 published marginals and Public Use File (FUP), INE information reused under the CC BY 4.0 licence; it is not official INE microdata and INE is not responsible for its content. The synthetic population is published by estimador.pt under the CC BY-NC 4.0 licence (Attribution-NonCommercial 4.0 International).

Attribution in Portuguese

Fonte: Instituto Nacional de Estatística, IP – Portugal (Recenseamento Geral da População e Habitação — Censos 2021; período de referência: 2021). Informação modificada: os dados aqui publicados são uma população sintética gerada por estimador.pt a partir das distribuições marginais publicadas e do Ficheiro de Uso Público (FUP) dos Censos 2021, informação do INE reutilizada ao abrigo da licença CC BY 4.0; não constituem microdados oficiais do INE e o INE não é responsável pelo seu conteúdo. A população sintética é publicada por estimador.pt ao abrigo da licença CC BY-NC 4.0 (Atribuição-NãoComercial 4.0 Internacional).

Cite as

estimador.pt, População Sintética de Portugal v1.0.3 (2026), CC BY-NC 4.0. https://github.com/estimadorpt/pt-synthpop/releases/tag/v1.0.3

The citation’s link is the release page on GitHub, which does not change. There is no DOI yet.

Found an error?

Corrections to this release are recorded in the errata. To report a problem, open a GitHub issue or write to info@estimador.pt. The model card has the full technical account.

How the population was made