Skip to contents

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

In the previous vignette we used make_agents() to create a synthetic population of individual agents from aggregate count data.

These agents often contain only a small number of variables. For example, a population may contain age-group and gender information but lack additional attributes required for simulation modelling.

The ReplicaAdder class can be used to enrich synthetic agents using contingency tables derived from external data sources.

Examples include:

  • education;

  • employment status;

  • occupation;

  • health status; and

  • income category.

This vignette demonstrates how to assign an education attribute while preserving known relationships between age, gender and education. The replica tools demonstrated here collectively represent an R implementation of the demographic attribute-assignment stage of the workflow described by de Mooij et al. (2024) for spatial synthetic population generation.

Workflow

The workflow demonstrated in this vignette can be summarised as:

Age-Gender Counts ↓ make_agents() ↓ Synthetic Agents ↓ ReplicaAdder ↓ Education Assignment ↓ Enriched Synthetic Population

Supply a seed synthetic population of individual agents

We begin with a basic synthetic population that lacks the target attribute.

For this example, we will create a basic seed population from an age group and gender contingency table using the approach demonstrated in the “Generating Synthetic Populations from Aggregated Data” vignette.

age_gender <- data.frame(

  age_group = c(
    "18-64",
    "18-64",
    "65+",
    "65+"
  ),

  gender = c(
    "Male",
    "Female",
    "Male",
    "Female"
  ),

  count = c(
    10,
    10,
    10,
    10
  )

)
age_gender
##   age_group gender count
## 1     18-64   Male    10
## 2     18-64 Female    10
## 3       65+   Male    10
## 4       65+ Female    10

We can now generate the basic seed population of synthetic agents:

population <- make_agents(age_gender)

The generated seed population now contains one row per synthetic agent.

head(population)
##    agent_id age_group gender
##      <char>    <char> <char>
## 1: Agent_01     18-64   Male
## 2: Agent_02     18-64   Male
## 3: Agent_03     18-64   Male
## 4: Agent_04     18-64   Male
## 5: Agent_05     18-64   Male
## 6: Agent_06     18-64   Male

We can verify that the generated population preserves the source distribution.

synthetic_population_to_contingency(population, 
                                    columns = c("age_group", "gender"))
##   age_group gender count
## 1     18-64   Male    10
## 2     18-64 Female    10
## 3       65+   Male    10
## 4       65+ Female    10

The population contains age and gender information but no education attribute.

Our goal is to assign education values while preserving known demographic relationships.

Supply a contingency table

The reference distribution is supplied as a contingency table. In real use, we would source contingency tables from high quality data sources (e.g., census data) representative of our regions of interest. In this example, we will generate an illustrative contingency table using hypothetical values.

contingency <- data.frame(

  age_group = c(
    "18-64", "18-64",
    "18-64", "18-64",
    "65+",   "65+",
    "65+",   "65+"
  ),

  gender = c(
    "Male",   "Male",
    "Female", "Female",
    "Male",   "Male",
    "Female", "Female"
  ),

  education = c(
    "Degree", "School",
    "Degree", "School",
    "Degree", "School",
    "Degree", "School"
  ),

  count = c(
    60, 40,
    55, 45,
    30, 70,
    25, 75
  )

)

The contingency table defines the expected education distribution within each age-group and gender combination.

For example:

18-64 Male Degree = 60% School = 40%

65+ Female Degree = 25% School = 75%

Create a ReplicaAdder

The assignment workflow is controlled using a ReplicaAdder.

adder <- ReplicaAdder(
  synth_pop = population,
  contingency = contingency,
  target_attribute = "education",
  group_by = c(
    "age_group",
    "gender"
  )
)

The object contains:

  • the synthetic population;

  • a reference contingency table;

  • the target attribute to be assigned; and

  • the conditioning variables used during assignment.

Handle missing groups

Real-world contingency tables often do not contain every combination of characteristics found in a synthetic population. For example, a synthetic population may contain demographic groups that do not appear in the source data.

replica supports several strategies for handling missing groups. The selected strategy is stored in the missing_group_strategy slot.

adder@missing_group_strategy
## [1] "borrow"

In the above example, the strategy is “borrow” (which is selected by default) that borrows information from nearby groups.

Other options are “overall” which uses the overall distribution of the target attribute and “error” which stops execution when a required group is missing. The most appropriate choice depends on the intended application and the completeness of the source data.

Run attribute assignment

The synthetic agents can now be enriched with an education attribute.

The assignment is performed using:

adder <- enhance(adder)

The workflow:

  • resolves missing contingency groups;

  • calculates group-specific proportions;

  • converts proportions into agent assignments;

  • assigns attribute values; and

  • validates the resulting distribution.

The updated synthetic population is stored in adder@synth_pop.

Inspect the enriched population

The synthetic population now contains the assigned education attribute.

head(adder@synth_pop)
##    agent_id age_group gender education
##      <char>    <char> <char>    <char>
## 1: Agent_01     18-64   Male    Degree
## 2: Agent_02     18-64   Male    Degree
## 3: Agent_03     18-64   Male    Degree
## 4: Agent_04     18-64   Male    Degree
## 5: Agent_05     18-64   Male    Degree
## 6: Agent_06     18-64   Male    School

We can examine the distribution of education values.

synthetic_population_to_contingency(adder@synth_pop, 
                                    columns = "education")
##   education count
## 1    Degree    17
## 2    School    23

The population has been enriched while preserving the demographic relationships specified in the reference contingency table.

We can also reconstruct the resulting contingency table:

synthetic_population_to_contingency(
  adder@synth_pop,
  columns = c("age_group", "gender","education"))
##   age_group gender education count
## 1     18-64   Male    Degree     6
## 2     18-64   Male    School     4
## 3     18-64 Female    School     4
## 4     18-64 Female    Degree     6
## 5       65+   Male    School     7
## 6       65+   Male    Degree     3
## 7       65+ Female    Degree     2
## 8       65+ Female    School     8

The assigned education values approximately reproduce the proportions defined in the reference contingency table.

Key takeaways

In this vignette we:

  • created a synthetic population;

  • defined a reference contingency table;

  • configured a ReplicaAdder;

  • assigned a new attribute using enhance();

  • explored strategies for handling missing groups;

  • added marginal distributions; and

  • verified the resulting synthetic population.

These tools provide a flexible framework for enriching synthetic populations using aggregate demographic data.

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