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 “Assigning Attributes Using Contingency Tables” vignette we used ReplicaAdder to enrich a synthetic population with additional demographic attributes.

At this stage each row of the synthetic population represents an individual agent.

Many simulation models, however, require agents to be organised into realistic household structures before analysis can proceed.

Examples include:

  • health-economic microsimulation models;

  • infectious disease models;

  • transport simulations; and

  • social and economic forecasting models.

The replica package provides tools for transforming an agent-level synthetic population into synthetic households while preserving geographic and demographic constraints. It does this by providing an R implementation of an algorithm described by de Mooij et al. (2024).

Household generation in replica is based on two core classes:

  • ReplicaStructure
  • ReplicaGrouper

A ReplicaStructure describes a household structure that should be generated, while a ReplicaGrouper applies one or more household definitions to a synthetic population.

This vignette demonstrates the third stage of the replica workflow: transforming individual synthetic agents into synthetic households.

Workflow overview

The workflow demonstrated in this vignette can be summarised as:

Aggregate Counts ↓ make_agents() ↓ Synthetic Agents ↓ ReplicaAdder ↓ Enriched Population ↓ ReplicaGrouper + ReplicaStructure ↓ Synthetic Households

This vignette focuses on the household-generation stage.

Supply a synthetic population of individual agents

This vignette assumes that a synthetic population has already been created and enriched with demographic attributes.

In practice such a population would typically have been generated using the workflows described in the “Generating Synthetic Populations from Aggregated Data” and “Assigning Attributes Using Contingency Tables” vignettes.

For simplicity, this example uses a small illustrative population containing four adults living in the same neighbourhood.

pop <- data.table(

  agent_id = c(
    "A001",
    "A002",
    "A003",
    "A004"
  ),

  neighb_code = c(
    "N1",
    "N1",
    "N1",
    "N1"
  ),

  age = c(
    40,
    35,
    50,
    45
  ),

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

  household_position = c(
    "Parent",
    "Parent",
    "Parent",
    "Parent"
  )

)
pop
##    agent_id neighb_code   age gender household_position
##      <char>      <char> <num> <char>             <char>
## 1:     A001          N1    40   Male             Parent
## 2:     A002          N1    35 Female             Parent
## 3:     A003          N1    50   Male             Parent
## 4:     A004          N1    45 Female             Parent

Household generation is driven by household positions.

These positions identify the household roles that agents may occupy and determine which agents are eligible for matching during household construction.

Potential examples include:

  • Parent
  • Child
  • Grandparent

In this example all agents are classified as potential parents and are therefore eligible for adult household positions.

Create a household type

A household type specifies a household structure that we plan to generate. Here we create a simple couple household.

hh <- ReplicaStructure("CoupleHousehold")

At this point we have only defined the household name. We now need to specify the household members that form this household type.

Define household membership

The renew() method defines the roles that must be filled when constructing a household. In this example, a couple household requires two adults.

hh <- renew(
  hh,
  household_position = "Parent",
  position_identifier = "adult",
  amount = 2,
  backup_position_identifiers = character()
)

This tells replica that:

  • agents with household position “Parent” are eligible;

  • these agents represent “adult” household members; and

  • exactly two adults are required per household.

Notice that two separate concepts are used:

  • household_position

  • position_identifier

The household_position corresponds to values that appear in the synthetic population.

The position_identifier defines broader household roles used internally by the household-building algorithm.

For example, multiple population-specific household positions could all be assigned the identifier "adult".

This separation makes it easier to adapt household generation rules to different source datasets.

The household definition is now complete.

Define demographic matching rules

The demographic characteristics assigned in the previous vignette can now be used when constructing households.

For example, household formation may depend on:

  • partner gender combinations;

  • partner age differences; and

  • child-parent age relationships.

These demographic relationships are controlled using matching distributions.

For simplicity, this illustrative example will generate Female - Male pairs in which the age gap between partners is within 5 years.

hh@couple_gender_distribution <- c("Female|Male" = 1)

hh@couple_age_distribution <- c("-5-5" = 1)

The above age distribution indicates that permissible partner age gaps range from five years younger to five years older.

In this example the four agents are expected to form two synthetic couple households:

  • one household containing agents A001 and A002; and
  • one household containing agents A003 and A004.

The exact assignment depends on the demographic matching rules specified above.

Create a household grouper

A ReplicaGrouper coordinates household generation across an entire synthetic population.

hg <- ReplicaGrouper(df_synth_pop = pop,
                       group_by = "neighb_code")

The group_by argument determines the geographic or administrative boundaries within which household generation will occur.

In this example households are generated independently within each neighbourhood.

Restricting household generation to geographic areas helps preserve local population structure and ensures that agents are matched only with other agents from the same area.

This is particularly important when generating synthetic households for geographically explicit simulation models.

Register household types

A ReplicaGrouper may contain multiple household types.

For example, a realistic population might contain:

  • single-adult households;

  • couple households; and

  • family households.

Household types are registered using renew().

hg <- renew(hg,hh)

The grouper now knows how to generate couple households.

Run household generation

Once household types have been registered, the complete household-generation workflow can be executed using enhance().

result <- enhance(hg)

The enhance() method executes the complete household-generation workflow.

For each grouping region (neighb_code in this example), replica:

  1. Identifies eligible household members.

  2. Creates household structures using registered ReplicaStructure objects.

  3. Matches adults according to the configured gender and age distributions.

  4. Creates synthetic households.

  5. Assigns household identifiers.

  6. Produces household-level summary tables.

The result is returned as a list containing both agent-level and household-level outputs.

Inspect output

The result now contains both agent-level and household-level outputs.

synthetic_population <- result$synthetic_population
synthetic_households <- result$synthetic_households

The household-generation workflow produces two complementary outputs.

synthetic_population contains one row per agent and records the household assignment of each synthetic individual.

synthetic_households contains one row per household and summarises the resulting household structures.

Together these outputs allow analyses to be performed at both the individual and household level.

Inspect household assignments

The agent-level output now contains household identifiers.

synthetic_population[,c("agent_id", "household_id")]
##    agent_id household_id
##      <char>       <char>
## 1:     A001    SSH000001
## 2:     A002    SSH000001
## 3:     A003    SSH000002
## 4:     A004    SSH000002

Agents sharing the same household identifier belong to the same synthetic household.

Inspect household-level summaries

The household summary table provides one row per household.

synthetic_households
##   household_id neighb_code         hh_type hh_size
## 1    SSH000001          N1 CoupleHousehold       2
## 2    SSH000002          N1 CoupleHousehold       2
nrow(synthetic_households)
## [1] 2

This value represents the number of synthetic households that were successfully generated.

Check integrity (brief version)

The household-generation workflow automatically performs validation checks during execution.

A simple post-generation check is:

any(
  is.na(
    synthetic_population$household_id
  )
)
## [1] FALSE

A value of FALSE indicates that all agents have been assigned to households.

A more comprehensive discussion of population validation is provided in the “Evaluating Synthetic Population Quality” vignette.

Create family households

The previous example generated households containing adults only. The same approach can be extended further to support more complex household structures involving grandparents, children or other household positions if suitable demographic data are available.

hh <- ReplicaStructure("FamilyHousehold")
hh <- renew(
  hh,
  household_position = "Parent",
  position_identifier = "adult",
  amount = 2,
  backup_position_identifiers = character()
)

hh <- renew(
  hh,
  household_position = "Child",
  position_identifier = "child",
  amount = 2,
  backup_position_identifiers = character()
)

When child household members are present, replica automatically:

  • forms sibling groups;

  • creates adult partner groups;

  • matches adults and children; and

  • creates complete family households.

No additional user intervention is required.

The resulting household structures are stored using separate adult, child and all components.

How the workflow fits together

The overall workflow can be summarised as:

Aggregate Counts ↓ make_agents() ↓ Synthetic Agents ↓ ReplicaAdder ↓ Enriched Population ↓ ReplicaStructure + ReplicaGrouper ↓ Synthetic Households ↓ Validation

Key takeaways

At this point the synthetic population contains both individual-level and household-level structures.

The resulting synthetic households can be used directly in simulation models or evaluated further using the validation tools described in the “Evaluating Synthetic Population Quality” vignette.

In this vignette we:

  • transformed synthetic agents into synthetic households;

  • defined household structures using ReplicaStructure;

  • specified household-member roles;

  • configured demographic matching rules;

  • generated households using ReplicaGrouper;

  • examined both agent-level and household-level outputs; and

  • created both couple and family household structures.

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