Skip to main content

people

people

The people in a sim (ss.People), lazy references to their properties (ss.person), and how they are made

People hold what every module shares, such as age, sex, and who is alive. In a compartmental run, each row is a group of people rather than an agent.

Used with: agents and compartments; declared and coded modules

Classes

Name Description
AgentScale The number of people each agent stands for relative to the others (people.scale); setting it other than 1 makes results, and the counts in a declared model’s rates (I.n, I.frac, and the fraction infectious in a transmission), add up the agents’ weights
LazyPeople The people’s properties, before there are any people: ss.person.<name> is a lazy reference to the property <name> of each person (e.g. ss.person.age, ss.person.urban), checked when the sim is built
MadeOnUse One of the four fundamental arrays of ss.People, made on first use (see People.make_uids())
People The people in a sim: their ages, sexes, who is alive, and the states that modules add to them; also how agents are born, die, and are counted
Person All the properties of one agent (see People.get_person()), as a dict that can be turned into a dataframe

AgentScale

people.AgentScale(name=None, **kwargs)

The number of people each agent stands for relative to the others (people.scale); setting it other than 1 makes results, and the counts in a declared model’s rates (I.n, I.frac, and the fraction infectious in a transmission), add up the agents’ weights

LazyPeople

people.LazyPeople()

The people’s properties, before there are any people: ss.person.<name> is a lazy reference to the property <name> of each person (e.g. ss.person.age, ss.person.urban), checked when the sim is built

It can be used in a condition (ss.person.age < 15, for who=) and, as the person’s value, in a rate, a branch probability, or a result (expit(b0 + b1*ss.person.urban)); a condition in a rate is 1 for the people it holds for and 0 for the others (0.3*(ss.person.age > 65)).

Examples

p_use = expit(b0 + b_age*ss.person.age + b_urban*ss.person.urban)
kids = ss.person.age < 15

Methods

Name Description
get ss.person.<name>, or default for everyone if nothing adds the property <name> to the people, e.g. one that a
get
people.LazyPeople.get(name, default)

ss.person.<name>, or default for everyone if nothing adds the property <name> to the people, e.g. one that a module adds (people.add_state()), read by a rate whether or not that module is in the sim

Parameters
Name Type Description Default
name str the name of the property required
default float the value for everyone if nothing adds the property required
Example
onset = S >> D @ ss.peryear(0.01)*(1 + 0.5*ss.person.get('unstable_housing', 0))

MadeOnUse

people.MadeOnUse()

One of the four fundamental arrays of ss.People, made on first use (see People.make_uids())

A descriptor rather than a branch of People.__getattr__(), so that a subclass with a __getattr__() of its own can’t hide it. It defines only __get__(), so once the arrays are made, the attribute in the instance’s __dict__ is found first and this costs nothing.

People

people.People(
    n_agents,
    age_data=None,
    extra_states=None,
    p_female=0.5,
    mock=False,
)

The people in a sim: their ages, sexes, who is alive, and the states that modules add to them; also how agents are born, die, and are counted

The sim usually makes this itself, from n_agents= (and total_pop=, the people they stand for). Give one yourself to give agents ages from data of your own (ss.People(n_agents, age_data=...)) or extra states; for the population of a place, use ss.population('Kenya'). In a compartmental run, each row is a group of people rather than an agent.

Parameters

Name Type Description Default
n_agents int the initial number of agents in the model required
age_data dataframe/series/array/str/ss.Dist the age distribution: a dataframe with columns age (the lower edge of each age bin) and value (the number or fraction of people in it), a series of values indexed by age, a two-column array, a CSV file with the dataframe’s columns, or a distribution of ages (default: the world’s ages). This gives agents ages; for age groups in a compartmental model, use disease.stratify(age={0: 0.3, 15: 0.6, 65: 0.1}) instead None
extra_states list more properties of each person, e.g. [ss.FloatArr('income')] (modules can also add them, with people.add_state()) None
p_female float the fraction of agents who are female 0.5
mock bool if True, link the people to a mock sim, so they can be used without one (for testing and debugging) False

Examples

ppl = ss.People(2000)
kids = ss.person.age < 15 # A lazy condition, for a sim run as agents or as compartments (see ss.person)

Attributes

Name Description
auto_state_list The people’s own ss.BoolState states (e.g. alive, female), each of which makes a result of the same name, the number of people in it
dead Whether each agent has died
grouped Whether these are the groups of a compartmental run (one row per group), not agents
male Whether each agent is male (~people.female; female is a state)
n The number of people alive now, under every solver, as sir.I.n counts the people in a state (the same as people.alive.n):
n_agents The number of active agents, as len(people) (for the number of people alive, see people.n)
n_uids The number of agents ever made, alive or not (each has its own UID)

Methods

Name Description
add_active Add agents to the active agents, in place where there is room (so a few births do not copy all of them)
add_module Add a module to the people: its states are registered, so that they grow with the agents, and the module is found in two ways
add_state Add a property of each person, from a module (e.g. a social determinant of health that several modules read, as ss.person.<name>)
age_bins The bin of each agent’s age, as np.digitize(age, edges), by UID: everyone gets older at each step, but few leave their bin, so only those who did are worked out again
born Tell each module that defines on_birth() about these newborns (see ss.Module.on_birth()); called wherever children are born
brief Print a one-line summary of the people
death_modules The modules whose on_death() is called at a death (see ss.Module.on_death()): the diseases, then any other declared module, then any other module that defines it
died_of The agents who died in this step of a cause (a module or a name), once each death is resolved to one cause (see request_death())
disp Print every attribute of the people
dying The agents who died or left in this step (see step_die()), who are active until the end of it
finish_step Remove dead agents and run post-step updates (in one pass over the agents, unless update_post() is changed)
get_age_dist The distribution that new agents’ ages are drawn from, made from age data
get_person All the properties of one agent, as an ss.people.Person
grow Add agents, e.g. newborns or immigrants, and return their UIDs
init_mock Link the people to a mock sim and give them their values, so they can be used without a sim (for testing and debugging)
init_results Make the results of the people; called by Sim.init_results()
init_vals Give each state its initial values (e.g. agents’ ages), the final step of initialization
keys The names of the people’s states, including those of modules (e.g. ‘sir.S’)
link_sim Link the people to the sim, and their distributions (e.g. of ages) to its random numbers; called by sim.init()
make_uids Make the four fundamental arrays: UIDs for tracking agents, slots for tracking random
phase Each agent’s phase, in [0, 1), by UID: a time between steps, t, is taken at step floor(t + phase), so it is rounded up
plot Plot the distribution of each of the people’s states: a histogram for numbers, and a bar chart for true/false
plot_ages Plot the age pyramid: the number or fraction of females and males in each age group
record_events Record the people who died or left in the step, at its index; they are taken out at the end of it (see finish_step()), whenever in the step it was requested
record_states Record the population counts at the start of the step (each ss.BoolState, e.g. alive, female), at its index (see ss.loop.Loop)
remove_dead Remove agents who are exiting the population (death, migration, etc)
request_death Request that agents die at this step; how a module kills agents
request_removal Request that agents leave the sim at this step for a reason other than death (e.g. emigration), so they are counted as having left (results.emigrated) rather than as having died
resolve_causes Give each agent who dies in this step one cause, from the deaths requested (see request_death()); called by step_die()
scale_flows The number of people some agents stand for, by their weights (people.scale), e.g. for a result that counts people rather than agents
slot_raw The slot of every agent, by UID, for a kernel; or None while the slots are the UIDs (see make_uids()), which have no array of their own
step_die Carry out the deaths and removals of this step (those requested in it, or set for it before), and return who died or left
taken_names The names of the attributes every People has (e.g. “age”, “version”), which a module can’t take from its variable
to_df Export to dataframe; 2D states have one column per value, e.g. sus_imm_0 (or sus_imm_wild if the columns are named)
unborn_uids The active agents not yet born, with a negative age (e.g. made at conception by ss.Pregnancy), who are not counted among the people (e.g. in the result alive)
update_post Updates at the end of each step: agents get older (see finish_step())
add_active
people.People.add_active(new_uids)

Add agents to the active agents, in place where there is room (so a few births do not copy all of them)

add_module
people.People.add_module(module)

Add a module to the people: its states are registered, so that they grow with the agents, and the module is found in two ways

  • People.<module> will be a reference to the module itself, enabling access via people.sir.S
  • People.states['<module>.<state>'] will be a reference to the state, enabling access via people.states['sir.S']
Parameters
Name Type Description Default
module Module the module to add required
add_state
people.People.add_state(state)

Add a property of each person, from a module (e.g. a social determinant of health that several modules read, as ss.person.<name>)

Idempotent: if the people have a property of that name already (added by another module, say), it is returned as it is, so each module that reads it can add it. Call it before the people’s values are made, e.g. in a module’s init_pre(); added later, its values are made at once.

Parameters
Name Type Description Default
state Arr the array, e.g. ss.BoolArr('housing', default=False) or ss.FloatArr('adherence', default=ss.uniform()) required
Returns
Name Type Description
The property’s array (the one given, or the one added before)
Example
def init_pre(self, sim):
    super().init_pre(sim)
    self.housing = sim.people.add_state(ss.BoolArr('housing', default=ss.bernoulli(0.8)))
age_bins
people.People.age_bins(edges)

The bin of each agent’s age, as np.digitize(age, edges), by UID: everyone gets older at each step, but few leave their bin, so only those who did are worked out again

born
people.People.born(children)

Tell each module that defines on_birth() about these newborns (see ss.Module.on_birth()); called wherever children are born

brief
people.People.brief(output=False)

Print a one-line summary of the people

Parameters
Name Type Description Default
output bool if True, return the text rather than printing it False
death_modules
people.People.death_modules()

The modules whose on_death() is called at a death (see ss.Module.on_death()): the diseases, then any other declared module, then any other module that defines it

died_of
people.People.died_of(cause)

The agents who died in this step of a cause (a module or a name), once each death is resolved to one cause (see request_death())

Parameters
Name Type Description Default
cause Module / str the module, or its name required
disp
people.People.disp()

Print every attribute of the people

dying
people.People.dying()

The agents who died or left in this step (see step_die()), who are active until the end of it

finish_step
people.People.finish_step()

Remove dead agents and run post-step updates (in one pass over the agents, unless update_post() is changed)

get_age_dist
people.People.get_age_dist(age_data)

The distribution that new agents’ ages are drawn from, made from age data

The data are a two-column array, a pandas series with age as the index and the number (or fraction) of people as the value, a dataframe with “age” and “value” columns, or the name of a CSV file with those columns, e.g.:

age      value
0      220.548
1      206.188
2      195.792
3      187.442

The ages are the lower edges of the bins, so ages within a bin are spread evenly. The last bin is as wide as the one before it; to set its upper edge, add a row with that age and a value of 0. Counts and fractions give the same distribution.

Parameters
Name Type Description Default
age_data array/series/dataframe/str/ss.Dist the data, as above, or a distribution of ages, used as it is (default: the world’s ages, ss.data.age('world'), as for a sim with no named population) required
Returns
Name Type Description
An ss.Dist of ages
get_person
people.People.get_person(ind)

All the properties of one agent, as an ss.people.Person

Parameters
Name Type Description Default
ind int the UID of the agent required
Examples
sim = ss.Sim(diseases='sir', networks='random', n_agents=100).run()
print(sim.people.get_person(5)) # The agent with UID 5
grow
people.People.grow(n=None, new_slots=None, placed=False, parent=None, age=None)

Add agents, e.g. newborns or immigrants, and return their UIDs

Parameters
Name Type Description Default
n int the number of agents to add (default: one for each of new_slots) None
new_slots array the slots of the new agents, which say which random numbers each draws (default: their UIDs) None
placed bool whether the caller gives them their levels of the sim’s stratifications; if not, they are drawn from each one’s split False
parent array the parent of each (e.g. for newborns), set before their levels are drawn, so they can be born where their parent is None
age array their age (e.g. 0 for newborns), likewise None
init_mock
people.People.init_mock()

Link the people to a mock sim and give them their values, so they can be used without a sim (for testing and debugging)

init_results
people.People.init_results()

Make the results of the people; called by Sim.init_results()

Each of the people’s own ss.BoolState states makes a result of the number in it (e.g. alive, the number alive); for a state that makes no result, use ss.BoolArr instead. There are also the flows of people who died and who left (died and emigrated; results.died.cum is the cumulative total).

With sim.pars.record_people=False, there are none of these (and record_states() and record_events() are skipped in the loop), which saves a little time and memory.

init_vals
people.People.init_vals()

Give each state its initial values (e.g. agents’ ages), the final step of initialization

keys
people.People.keys()

The names of the people’s states, including those of modules (e.g. ‘sir.S’)

make_uids
people.People.make_uids()

Make the four fundamental arrays: UIDs for tracking agents, slots for tracking random numbers, AUIDs for tracking alive agents, and agents’ parents

They are made on first use rather than in __init__(), so that a People not yet in a sim (such as the copy a sim keeps of itself before it is initialized, for sim.new()) holds no arrays per agent. The slots read the UIDs, and the parents are all none, until one is set (see shared in ss.Arr), so they take no memory unless something (e.g. ss.Pregnancy, with fetuses as agents) sets them.

phase
people.People.phase(uids=None)

Each agent’s phase, in [0, 1), by UID: a time between steps, t, is taken at step floor(t + phase), so it is rounded up or down at random in proportion (2.3 steps is 2 for 70% of agents and 3 for the rest), keeping its mean, with no draws: both a time due in a disease written as code (ss.TimeArr.due()) and a dwell time of the agent engine. Spread evenly over the slots (so an agent has the same phase in every scenario), and shifted by the sim’s seed

Parameters
Name Type Description Default
uids uids the agents to give the phases of (worked out for them alone); by default, every agent’s, kept until agents are made None
plot
people.People.plot(
    key=None,
    alive=True,
    bins=50,
    hist_kw=None,
    max_plots=20,
    figsize=(16, 12),
    **kwargs,
)

Plot the distribution of each of the people’s states: a histogram for numbers, and a bar chart for true/false

Parameters
Name Type Description Default
key str / list the state(s) to plot (default: all, up to max_plots) None
alive bool if False, include every agent ever made, not only those active True
bins int the number of bins to use in plt.hist() 50
hist_kw dict passed to plt.hist() None
max_plots int the maximum number of plots to create 20
figsize tuple passed to plt.figure(); by default large since the plots are crowded (16, 12)
**kwargs dict passed to sc.getrowscols(), including fig_kw
plot_ages
people.People.plot_ages(bins=None, absolute=False, fig_kw=None)

Plot the age pyramid: the number or fraction of females and males in each age group

Parameters
Name Type Description Default
bins list / int the edges of the age groups, or the width of each (default: 5-year groups up to the oldest age) None
absolute bool whether to show absolute numbers or percentage of the population False
fig_kw dict passed to plt.subplots() None
Examples
sim = ss.demo(plot=False)
sim.people.plot_ages()
record_events
people.People.record_events()

Record the people who died or left in the step, at its index; they are taken out at the end of it (see finish_step()), whenever in the step it was requested

record_states
people.People.record_states()

Record the population counts at the start of the step (each ss.BoolState, e.g. alive, female), at its index (see ss.loop.Loop)

remove_dead
people.People.remove_dead(aging=False)

Remove agents who are exiting the population (death, migration, etc)

Parameters
Name Type Description Default
aging bool also age the agents who remain (as update_post() does), in the same pass over them False
request_death
people.People.request_death(uids, cause=None, hazard=None)

Request that agents die at this step; how a module kills agents

Use this rather than setting People.ti_dead directly, so that modules don’t overwrite each other’s deaths (e.g. a death set for the future overwriting one due now from another module). A module with a future time of death (e.g. after the course of a disease) keeps it itself, and calls this when the time comes, with itself as the cause.

The deaths happen after every module has stepped, but before the analyzers, so that analyzers can see and record the agents who died in this step.

Each person dies once, of one cause: if several modules request the death of the same person in the same step, one of them is chosen at random (whatever the order of the modules, with common random numbers): in proportion to the hazards of the claims if each gave one (hazard=), and otherwise each equally likely. The cause is kept in people.cause_of_death (see people.causes). A module counts its deaths after they are resolved, with people.died_of(module), so a death is counted once.

Parameters
Name Type Description Default
uids array the agents who die required
cause Module / str what they die of: a module (by its name) or a name (default: none) None
hazard float / array the hazard of this death, one number or one per agent (in any unit, the same for every module, e.g. per year), to weight the choice of cause among the claims on the same person in the step (e.g. dis.death.hazard(uids) for a declared transition) None
request_removal
people.People.request_removal(uids)

Request that agents leave the sim at this step for a reason other than death (e.g. emigration), so they are counted as having left (results.emigrated) rather than as having died

Parameters
Name Type Description Default
uids array the agents to remove required
resolve_causes
people.People.resolve_causes(death_uids)

Give each agent who dies in this step one cause, from the deaths requested (see request_death()); called by step_die()

scale_flows
people.People.scale_flows(inds)

The number of people some agents stand for, by their weights (people.scale), e.g. for a result that counts people rather than agents

Parameters
Name Type Description Default
inds array the agents to count required
slot_raw
people.People.slot_raw()

The slot of every agent, by UID, for a kernel; or None while the slots are the UIDs (see make_uids()), which have no array of their own

step_die
people.People.step_die()

Carry out the deaths and removals of this step (those requested in it, or set for it before), and return who died or left

taken_names
people.People.taken_names()

The names of the attributes every People has (e.g. “age”, “version”), which a module can’t take from its variable

to_df
people.People.to_df()

Export to dataframe; 2D states have one column per value, e.g. sus_imm_0 (or sus_imm_wild if the columns are named)

unborn_uids
people.People.unborn_uids()

The active agents not yet born, with a negative age (e.g. made at conception by ss.Pregnancy), who are not counted among the people (e.g. in the result alive)

update_post
people.People.update_post()

Updates at the end of each step: agents get older (see finish_step())

Person

people.Person()

All the properties of one agent (see People.get_person()), as a dict that can be turned into a dataframe

Examples

sim = ss.Sim(diseases='sir', networks='random', n_agents=100).run()
print(sim.people.get_person(5)) # The agent with UID 5

Methods

Name Description
to_df The properties as a dataframe, one row each
to_df
people.Person.to_df()

The properties as a dataframe, one row each

Functions

Name Description
population A named population: the size, age structure, and sex ratio of a country or a US state

population

people.population(place, year=None, n_agents=None, revision=None)

A named population: the size, age structure, and sex ratio of a country or a US state

The data are the UN World Population Prospects, bundled with starsim_data (for a US state, the US Census for 2023, downloaded on first use: see ss.data.population()). The sim takes its population size (total_pop) from them, unless it is given one, and the split of an age stratification that is not given one, so a compartmental model can use a named population as well as agents can. Where the population came from is shown by sim.describe().

Parameters

Name Type Description Default
place str a country, by name or code (‘Kenya’, ‘KE’, ‘KEN’), or a US state (‘United States:Massachusetts’) required
year int the year (default: the year the sim starts, if it has dates; otherwise the year of the WPP revision, e.g. 2024); years between the decadal values are interpolated None
n_agents int the number of agents (default: the sim’s); giving it makes the model agent-based, as ss.People(n_agents) does None
revision str the WPP revision (default: the latest bundled) None

Returns

Name Type Description
An ss.People, with ppl.named saying where it came from

Examples

sim = ss.Sim(sir, people=ss.population('Kenya', year=2024), networks=ss.contacts('Kenya'))
ss.population('NG').named.total # The population of Nigeria in 2024