Note - the replica library is currently very experimental. It is still undergoing active development and testing. Function, class and method names, arguments and syntax may change without the use of deprecation conventions. This library should currently be used only for exploratory purposes.
Motivation
Synthetic population generation often begins with aggregate population statistics rather than individual-level records.
Examples include:
population counts by neighbourhood;
age-group marginals;
demographic contingency tables;
census tabulations.
The first step in many population-synthesis workflows is to convert these aggregate counts into a synthetic population of individual agents.
The make_agents() function performs this task by
expanding aggregate counts into one row per synthetic individual. This
function aims to implement in R the initial step of an algorithm
described by de Mooij et al. (2024).
This vignette demonstrates how to create synthetic agents from
marginal distributions and contingency tables and shows how these agents
can subsequently be enriched and grouped using the remainder of the
replica workflow.
Introduction
The workflow supported by replica can be summarised
as:
Aggregate Counts ↓ make_agents() ↓ Synthetic Agents ↓ ReplicaAdder ↓ ReplicaGrouper ↓ Validation
This vignette focuses on the first stage: creating a synthetic population of individual agents.
Example 1: Creating agents from a spatial marginal
Suppose we know the number of residents in each neighbourhood.
neighbourhoods <- data.frame(neighb_code = c( "N1", "N2", "N3" ),
count = c( 100, 150, 75 ) )
neighbourhoods## neighb_code count
## 1 N1 100
## 2 N2 150
## 3 N3 75
The table contains aggregate counts rather than individual agents. We can convert this table to a table of individual agents:
agents <- make_agents(
neighbourhoods
)
head(agents)## agent_id neighb_code
## <char> <char>
## 1: Agent_001 N1
## 2: Agent_002 N1
## 3: Agent_003 N1
## 4: Agent_004 N1
## 5: Agent_005 N1
## 6: Agent_006 N1
Each row now represents a synthetic individual.
We can confirm the number of generated agents:
nrow(agents)## [1] 325
The generated population can also be aggregated back into a contingency table.
synthetic_population_to_contingency(
agents,
"neighb_code"
)## neighb_code count
## 1 N1 100
## 2 N2 150
## 3 N3 75
The reconstructed counts should match the source table used to generate the agents.
Example 2: Creating agents from an age marginal
The same function can be used with any marginal distribution.
age_margin <- data.frame(
age_group = c(
"0-17",
"18-64",
"65+"
),
count = c(
200,
600,
200
)
)
age_margin## age_group count
## 1 0-17 200
## 2 18-64 600
## 3 65+ 200
agents <- make_agents(
age_margin
)
head(agents)## agent_id age_group
## <char> <char>
## 1: Agent_0001 0-17
## 2: Agent_0002 0-17
## 3: Agent_0003 0-17
## 4: Agent_0004 0-17
## 5: Agent_0005 0-17
## 6: Agent_0006 0-17
Each synthetic agent now contains an age-group assignment.
Summarise the resulting population:
synthetic_population_to_contingency(
agents,
"age_group"
)## age_group count
## 1 0-17 200
## 2 18-64 600
## 3 65+ 200
Example 3: Creating agents from a contingency table
More detailed synthetic populations can be generated from contingency tables.
age_gender <- data.frame(
age_group = c(
"0-17",
"0-17",
"18-64",
"18-64",
"65+",
"65+"
),
gender = c(
"Male",
"Female",
"Male",
"Female",
"Male",
"Female"
),
count = c(
100,
90,
310,
290,
110,
100
)
)
age_gender## age_group gender count
## 1 0-17 Male 100
## 2 0-17 Female 90
## 3 18-64 Male 310
## 4 18-64 Female 290
## 5 65+ Male 110
## 6 65+ Female 100
Generate agents:
agents <- make_agents(
age_gender
)Inspect the resulting population:
head(agents)## agent_id age_group gender
## <char> <char> <char>
## 1: Agent_0001 0-17 Male
## 2: Agent_0002 0-17 Male
## 3: Agent_0003 0-17 Male
## 4: Agent_0004 0-17 Male
## 5: Agent_0005 0-17 Male
## 6: Agent_0006 0-17 Male
We can compare the generated population with the original contingency table.
synthetic_population_to_contingency(agents,
columns = c("age_group", "gender"))## age_group gender count
## 1 0-17 Male 100
## 2 0-17 Female 90
## 3 18-64 Male 310
## 4 18-64 Female 290
## 5 65+ Male 110
## 6 65+ Female 100
The reconstructed contingency table should reproduce the original counts exactly.
This property makes make_agents() a useful foundation for more sophisticated synthetic-population workflows.
Add agent attributes
The agents created by make_agents() typically contain only a subset of the characteristics required by a simulation model.
Additional attributes can be assigned using
ReplicaAdder. The use of this class is demonstrated in the
“Assigning Attributes Using Contingency Tables” vignette.
Assign agents to households
After additional attributes have been assigned, agents can be grouped into households.
To do this, use the ReplicaStructure and
ReplicaGrouper classes. These are described in another
vignette.
Key takeaways
In this vignette we:
introduced synthetic-agent generation;
created agents from spatial marginals;
created agents from demographic marginals;
created agents from contingency tables;
verified that aggregate distributions were preserved;
connected agent generation to the broader
replicaworkflow.
References
de Mooij J, Sonnenschein T, Pellegrino M, Dastani M, Ettema D, Logan B and Verstegen JA (2024).
GenSynthPop: generating a spatially explicit synthetic population of individuals and households from aggregated data.
Autonomous Agents and Multi-Agent Systems. https://link.springer.com/article/10.1007/s10458-024-09680-7
