1919@orca .step (STEP_NAME )
2020def employment (persons ):
2121 """
22- Executes the `enter_` and `exit_laborforce` estimated models to determine which unemployed
23- persons change to employed and which employed change to unemployed. Elegible persons are those
24- 18 years or older.
22+ Simulate labor force transitions for eligible persons.
2523
26- The `earning` column stores the annual income of each individual. For those unemployed, `earning` is set
27- to 0, for the rest, the `new_earning` lazily-computed orca column is used to determine the new income.
24+ This step applies estimated models to determine which unemployed persons become employed
25+ and which employed persons exit the workforce. Only persons aged 18 or older are considered.
26+ The function updates the `worker` and `earning` columns in the `persons` table.
2827
29- **Required tables:**
30- - persons
28+ Parameters
29+ ----------
30+ persons : orca.Table
31+ The persons table containing individual-level attributes.
3132
32- **Modifies State Variables:**
33- - persons.worker
34- - persons.earning
33+ Notes
34+ -----
35+ - Requires the `persons` table with columns: `age`, `worker`, `earning`.
36+ - Modifies `persons.worker` and `persons.earning` in place.
37+ - Uses module configuration from the TOML config file.
38+ - Triggers caching of the `income_dist` table for income assignment.
39+
40+ Example
41+ -------
42+ This step is executed as part of the annual simulation loop:
43+ `orca.run(['employment'], iter_vars=[...])`
3544 """
3645 start_time = time .time ()
3746
@@ -63,14 +72,38 @@ def employment(persons):
6372
6473def sample_income (mean , std ):
6574 """
66- Auxiliary function to sample from a lognormal distribution
75+ Draw samples from a lognormal distribution.
76+
77+ Parameters
78+ ----------
79+ mean : float or array-like
80+ The mean(s) of the underlying normal distribution.
81+ std : float or array-like
82+ The standard deviation(s) of the underlying normal distribution.
83+
84+ Returns
85+ -------
86+ float or np.ndarray
87+ Sample(s) from the lognormal distribution.
6788 """
6889 return np .random .lognormal (mean , std )
6990
7091
7192def run_and_calibrate_in_workforce_model (persons : pd .DataFrame , calibration_procedure : CalibrationConfig ) -> pd .Series :
7293 """
73- Execute `enter_labor_force` estimated model on elegible people according to the calibration procedure.
94+ Run the 'enter_labor_force' estimated model for eligible persons.
95+
96+ Parameters
97+ ----------
98+ persons : pandas.DataFrame
99+ DataFrame of persons with required model variables.
100+ calibration_procedure : CalibrationConfig or None
101+ Calibration procedure to apply, if any.
102+
103+ Returns
104+ -------
105+ pandas.Series
106+ Model predictions for each eligible person (0 = remain unemployed, 1 = become employed).
74107 """
75108 # Get model data
76109 model = mm .get_step ("enter_labor_force" )
@@ -86,7 +119,19 @@ def run_and_calibrate_in_workforce_model(persons: pd.DataFrame, calibration_proc
86119
87120def run_and_calibrate_out_workforce_model (persons : pd .DataFrame , calibration_procedure : CalibrationConfig ) -> pd .Series :
88121 """
89- Execute `exit_labor_force` estimated model on elegible people according to the calibration procedure.
122+ Run the 'exit_labor_force' estimated model for eligible persons.
123+
124+ Parameters
125+ ----------
126+ persons : pandas.DataFrame
127+ DataFrame of persons with required model variables.
128+ calibration_procedure : CalibrationConfig or None
129+ Calibration procedure to apply, if any.
130+
131+ Returns
132+ -------
133+ pandas.Series
134+ Model predictions for each eligible person (0 = remain employed, 1 = become unemployed).
90135 """
91136 # Get model data
92137 model = mm .get_step ("exit_labor_force" )
@@ -102,7 +147,19 @@ def run_and_calibrate_out_workforce_model(persons: pd.DataFrame, calibration_pro
102147
103148def run_simultaenous_calibration (persons : pd .DataFrame , simultaneous_calibration_config : SimultaneousCalibrationConfig ) -> pd .Series :
104149 """
105- Execute both `enter_labor_force` and `exit_labor_force` estimated models on elegible people according to the calibration procedure.
150+ Run simultaneous calibration for both 'enter' and 'exit' labor force models.
151+
152+ Parameters
153+ ----------
154+ persons : pandas.DataFrame
155+ DataFrame of persons with required model variables.
156+ simultaneous_calibration_config : SimultaneousCalibrationConfig
157+ Configuration for simultaneous calibration.
158+
159+ Returns
160+ -------
161+ tuple of pandas.Series
162+ Predictions for entering and exiting the workforce.
106163 """
107164 # Get enter model data
108165 enter_model = mm .get_step ("enter_labor_force" )
@@ -156,30 +213,68 @@ def run_simultaenous_calibration(persons: pd.DataFrame, simultaneous_calibration
156213@orca .column (table_name = "persons" )
157214def new_earning (persons , income_dist ):
158215 """
159- Sample income for new workers according to income distribution (`income_dist`) computed from the original synthetic population.
160- The income distribution is computed once and cached to be used in `new_earning` calls.
216+ Compute new earnings for persons entering the workforce.
217+
218+ For each eligible person, samples income from a lognormal distribution
219+ parameterized by age and education group, using the cached `income_dist` table.
220+
221+ Parameters
222+ ----------
223+ persons : orca.Table
224+ The persons table.
225+ income_dist : orca.Table
226+ Table with income distribution parameters.
161227
162- Click `[source]` (top right) for more details
228+ Returns
229+ -------
230+ pandas.Series
231+ Sampled earnings for each person.
163232 """
164233 persons_df = persons .to_frame (["age_group" , "education_group" ])
165234 merged_df = persons_df .merge (income_dist .local , on = ['age_group' , 'education_group' ], how = 'left' )
166235 return pd .Series (sample_income (merged_df ["mu" ], merged_df ["sigma" ]), index = persons_df .index )
167236
237+
168238@orca .column (table_name = "households" )
169239def hh_workers (persons ):
170240 """
171- Number of workers per household
241+ Compute the number of workers per household.
242+
243+ Parameters
244+ ----------
245+ persons : orca.Table
246+ The persons table.
247+
248+ Returns
249+ -------
250+ pandas.Series
251+ Categorical summary: "none", "one", or "two or more" workers per household.
172252 """
173253 return persons .to_frame (["household_id" , "worker" ]) \
174254 .groupby ("household_id" ) \
175255 .sum ()["worker" ] \
176256 .apply (lambda r : "none" if r == 0 else
177257 ("one" if r == 1 else "two or more" ))
178258
259+
179260@orca .column (table_name = "households" )
180261def income (persons ):
181262 """
182- Household-level income from person-level income. NOTE: This is for HOUSEHOLDS table
263+ Aggregate household income from person-level earnings.
264+
265+ Parameters
266+ ----------
267+ persons : orca.Table
268+ The persons table.
269+
270+ Returns
271+ -------
272+ pandas.Series
273+ Total income per household.
274+
275+ Notes
276+ -----
277+ This is for `HOUSEHOLDS` table
183278 """
184279 return persons .to_frame (["household_id" , "earning" ]) \
185280 .groupby ("household_id" ) \
@@ -188,9 +283,19 @@ def income(persons):
188283@orca .table (cache = True , cache_scope = 'forever' )
189284def income_dist (persons ):
190285 """
191- This table is computed the first time it is called, and stores the average and standard deviation of the income
192- of workers at the beginning of the simulation by age and education group. These values are used in the employment
193- model to assign an income for people that get into the workforce.
286+ Compute and cache income distribution parameters by age and education group.
287+
288+ This table is used to sample earnings for new workers in the employment model.
289+
290+ Parameters
291+ ----------
292+ persons : orca.Table
293+ The persons table.
294+
295+ Returns
296+ -------
297+ pandas.DataFrame
298+ DataFrame with columns: age_group, education_group, data_mean, data_std, mu, sigma.
194299 """
195300 income_dist = persons .to_frame (["worker" , "age_group" , "education_group" , "earning" ])[persons ["worker" ]== 1 ]\
196301 .groupby (['age_group' , 'education_group' ]).agg (
0 commit comments