@@ -46,7 +46,7 @@ def determine_escorting_participants(choosers, persons, model_settings):
4646
4747 # can specify different weights to determine chaperones
4848 persontype_weight = model_settings .get ("PERSON_WEIGHT" , 100 )
49- gender_weight = model_settings .get ("PERSON_WEIGHT " , 10 )
49+ gender_weight = model_settings .get ("GENDER_WEIGHT " , 10 )
5050 age_weight = model_settings .get ("AGE_WEIGHT" , 1 )
5151
5252 # can we move all of these to a config file?
@@ -122,7 +122,7 @@ def add_prev_choices_to_choosers(choosers, choices, alts, stage):
122122 stage_alts ,
123123 how = "left" ,
124124 left_on = escorting_choice ,
125- right_on = stage_alts . index . name ,
125+ right_index = True ,
126126 )
127127 .set_index ("household_id" )
128128 )
@@ -198,8 +198,12 @@ def create_school_escorting_bundles_table(choosers, tours, stage):
198198 bundles : pd.DataFrame
199199 one school escorting bundle per row
200200 """
201- # making a table of bundles
202- choosers = choosers .reset_index ()
201+ # want to keep household_id in columns, which is already there if running in estimation mode
202+ if "household_id" in choosers .columns :
203+ choosers = choosers .reset_index (drop = True )
204+ else :
205+ choosers = choosers .reset_index ()
206+ # creating a row for every school escorting bundle
203207 choosers = choosers .loc [choosers .index .repeat (choosers ["nbundles" ])]
204208
205209 bundles = pd .DataFrame ()
@@ -362,7 +366,11 @@ def school_escorting(
362366 households_merged = households_merged .to_frame ()
363367 tours = tours .to_frame ()
364368
365- alts = simulate .read_model_alts (model_settings ["ALTS" ], set_index = "Alt" )
369+ # FIXME setting index as "Alt" causes crash in estimation mode...
370+ # happens in joint_tour_frequency_composition too!
371+ # alts = simulate.read_model_alts(model_settings["ALTS"], set_index="Alt")
372+ alts = simulate .read_model_alts (model_settings ["ALTS" ], set_index = None )
373+ alts .index = alts ["Alt" ].values
366374
367375 households_merged , participant_columns = determine_escorting_participants (
368376 households_merged , persons , model_settings
@@ -379,7 +387,9 @@ def school_escorting(
379387 choices = None
380388 for stage_num , stage in enumerate (school_escorting_stages ):
381389 stage_trace_label = trace_label + "_" + stage
382- estimator = estimation .manager .begin_estimation ("school_escorting_" + stage )
390+ estimator = estimation .manager .begin_estimation (
391+ model_name = "school_escorting_" + stage , bundle_name = "school_escorting"
392+ )
383393
384394 model_spec_raw = simulate .read_model_spec (
385395 file_name = model_settings [stage .upper () + "_SPEC" ]
@@ -434,9 +444,26 @@ def school_escorting(
434444
435445 if estimator :
436446 estimator .write_model_settings (model_settings , model_settings_file_name )
437- estimator .write_spec (model_settings )
438- estimator .write_coefficients (coefficients_df , model_settings )
447+ estimator .write_spec (model_settings , tag = stage .upper () + "_SPEC" )
448+ estimator .write_coefficients (
449+ coefficients_df , file_name = stage .upper () + "_COEFFICIENTS"
450+ )
439451 estimator .write_choosers (choosers )
452+ estimator .write_alternatives (alts , bundle_directory = True )
453+
454+ # FIXME #interaction_simulate_estimation_requires_chooser_id_in_df_column
455+ # shuold we do it here or have interaction_simulate do it?
456+ # chooser index must be duplicated in column or it will be omitted from interaction_dataset
457+ # estimation requires that chooser_id is either in index or a column of interaction_dataset
458+ # so it can be reformatted (melted) and indexed by chooser_id and alt_id
459+ assert choosers .index .name == "household_id"
460+ assert "household_id" not in choosers .columns
461+ choosers ["household_id" ] = choosers .index
462+
463+ # FIXME set_alt_id - do we need this for interaction_simulate estimation bundle tables?
464+ estimator .set_alt_id ("alt_id" )
465+
466+ estimator .set_chooser_id (choosers .index .name )
440467
441468 log_alt_losers = config .setting ("log_alt_losers" , False )
442469
@@ -474,47 +501,72 @@ def school_escorting(
474501
475502 if stage_num >= 1 :
476503 choosers ["Alt" ] = choices
477- choosers = choosers .join (alts , how = "left" , on = "Alt" )
504+ choosers = choosers .join (alts . set_index ( "Alt" ) , how = "left" , on = "Alt" )
478505 bundles = create_school_escorting_bundles_table (
479506 choosers [choosers ["Alt" ] > 1 ], tours , stage
480507 )
481508 escort_bundles .append (bundles )
482509
510+ pipeline .replace_table ("households" , households )
511+
483512 escort_bundles = pd .concat (escort_bundles )
484- escort_bundles ["bundle_id" ] = (
485- escort_bundles ["household_id" ] * 10
486- + escort_bundles .groupby ("household_id" ).cumcount ()
487- + 1
488- )
489- escort_bundles .sort_values (
490- by = ["household_id" , "school_escort_direction" ],
491- ascending = [True , False ],
492- inplace = True ,
493- )
494513
495- school_escort_tours = school_escort_tours_trips .create_pure_school_escort_tours (
496- escort_bundles
497- )
498- chauf_tour_id_map = {
499- v : k for k , v in school_escort_tours ["bundle_id" ].to_dict ().items ()
500- }
501- escort_bundles ["chauf_tour_id" ] = np .where (
502- escort_bundles ["escort_type" ] == "ride_share" ,
503- escort_bundles ["first_mand_tour_id" ],
504- escort_bundles ["bundle_id" ].map (chauf_tour_id_map ),
505- )
514+ # Only want to create bundles and tours and trips if at least one household has school escorting
515+ if len (escort_bundles ) > 0 :
516+ escort_bundles ["bundle_id" ] = (
517+ escort_bundles ["household_id" ] * 10
518+ + escort_bundles .groupby ("household_id" ).cumcount ()
519+ + 1
520+ )
521+ escort_bundles .sort_values (
522+ by = ["household_id" , "school_escort_direction" ],
523+ ascending = [True , False ],
524+ inplace = True ,
525+ )
506526
507- tours = school_escort_tours_trips .add_pure_escort_tours (tours , school_escort_tours )
508- tours = school_escort_tours_trips .process_tours_after_escorting_model (
509- escort_bundles , tours
510- )
527+ school_escort_tours = school_escort_tours_trips .create_pure_school_escort_tours (
528+ escort_bundles
529+ )
530+ chauf_tour_id_map = {
531+ v : k for k , v in school_escort_tours ["bundle_id" ].to_dict ().items ()
532+ }
533+ escort_bundles ["chauf_tour_id" ] = np .where (
534+ escort_bundles ["escort_type" ] == "ride_share" ,
535+ escort_bundles ["first_mand_tour_id" ],
536+ escort_bundles ["bundle_id" ].map (chauf_tour_id_map ),
537+ )
511538
512- school_escort_trips = school_escort_tours_trips .create_school_escort_trips (
513- escort_bundles
514- )
539+ tours = school_escort_tours_trips .add_pure_escort_tours (
540+ tours , school_escort_tours
541+ )
542+ tours = school_escort_tours_trips .process_tours_after_escorting_model (
543+ escort_bundles , tours
544+ )
545+
546+ school_escort_trips = school_escort_tours_trips .create_school_escort_trips (
547+ escort_bundles
548+ )
549+
550+ else :
551+ # create empty school escort tours & trips tables to be used downstream
552+ tours ["school_esc_outbound" ] = pd .NA
553+ tours ["school_esc_inbound" ] = pd .NA
554+ tours ["school_escort_direction" ] = pd .NA
555+ tours ["next_pure_escort_start" ] = pd .NA
556+ school_escort_tours = pd .DataFrame (columns = tours .columns )
557+ trip_cols = [
558+ "household_id" ,
559+ "person_id" ,
560+ "tour_id" ,
561+ "trip_id" ,
562+ "outbound" ,
563+ "depart" ,
564+ "purpose" ,
565+ "destination" ,
566+ ]
567+ school_escort_trips = pd .DataFrame (columns = trip_cols )
515568
516569 # update pipeline
517- pipeline .replace_table ("households" , households )
518570 pipeline .replace_table ("tours" , tours )
519571 pipeline .get_rn_generator ().drop_channel ("tours" )
520572 pipeline .get_rn_generator ().add_channel ("tours" , tours )
0 commit comments