-
Notifications
You must be signed in to change notification settings - Fork 118
🚀 [feat] vehicle type model #486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
cb5169a
vehicle type model, first commit
mxndrwgrdnr 2fbd161
vehicle type model, first commit
mxndrwgrdnr 82e7e4c
option 2 spec changes
mxndrwgrdnr d0572a3
got vehicle choice model running w probabilistic dimension
mxndrwgrdnr 4260fb9
update example mtc configs to run vehicle choice
mxndrwgrdnr 72404f0
got vehicle choice model running w probabilistic dimension
mxndrwgrdnr cec3e4e
pycodestyle fixes and mi to meters conversion
mxndrwgrdnr 6d6f9e7
add veh choice to estimation example
mxndrwgrdnr 0ed8c5d
implemented option 2 and 4 as MNL
mxndrwgrdnr 5c5540d
simply veh type choice alts/utilities creation
mxndrwgrdnr d629401
fix alt file storage bug
mxndrwgrdnr 5f626d7
pycodestyle fixes
mxndrwgrdnr 349c904
pycodestyle fixes
mxndrwgrdnr 5ee4d17
pycodestyle fixes
mxndrwgrdnr ac1c934
debug estimation example
mxndrwgrdnr 8118466
estimation mode debug
mxndrwgrdnr f29f690
docstrings, etc
mxndrwgrdnr 3c4bc5a
typo
mxndrwgrdnr 665c4a2
veh typ choice yaml updates
mxndrwgrdnr 3c874bb
pycodestyle fixes
mxndrwgrdnr 832fc30
added vehicle type data, implemented option 4 minus owned veh interac…
dhensle 1b1dd54
implemented option4
dhensle 6660ab4
implemented vehicle type option 2 and vehicle allocation models
dhensle d1d3284
tied vehicle ids to household ids, added fleet_year option
a9da22f
added options to include vehicle data in vehicle table, documentation
3130d68
added annotate tours functionality
235c4fa
cleanup & documentation
498c09f
restore example_mtc
3a9542b
created example_mtc_extended
4be57ee
vehicle type model documentation
9583f38
documentation
dhensle e8b0d23
adding missed vehicle allocation spec
dhensle b078369
updating regress tables with new auto ownership costs
dhensle 990876d
fixed bug where chargers were applied to all alts and not just evs
dhensle f55c2f0
fixing incorrect coefficients
dhensle 75d4e7d
responses to pull request comments
dhensle 7d0a467
small variable name change
dhensle 81010ee
log_alt_losers setting
dhensle e497f65
Merge branch 'develop' into vehicle
dhensle e7b7c0e
pycodestyle
dhensle 691205d
no vehicle type estimation
dhensle 9c5753f
adding MTC Extended Example to TravisCI
dhensle fe4f763
removing unused expressions
dhensle d556239
replaced table with correct column order
dhensle File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,236 @@ | ||
| # ActivitySim | ||
| # See full license in LICENSE.txt. | ||
|
|
||
| import logging | ||
|
|
||
| import pandas as pd | ||
| import numpy as np | ||
| import itertools | ||
| import os | ||
|
|
||
| from activitysim.core.interaction_simulate import interaction_simulate | ||
| from activitysim.core import simulate | ||
| from activitysim.core import tracing | ||
| from activitysim.core import config | ||
| from activitysim.core import inject | ||
| from activitysim.core import pipeline | ||
| from activitysim.core import expressions | ||
| from activitysim.core import logit | ||
| from activitysim.core import assign | ||
| from activitysim.core import los | ||
|
|
||
| from activitysim.core.util import assign_in_place | ||
|
|
||
| from .util.mode import mode_choice_simulate | ||
| from .util import estimation | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def annotate_vehicle_allocation(model_settings, trace_label): | ||
| """ | ||
| Add columns to the tours table in the pipeline according to spec. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| model_settings : dict | ||
| trace_label : str | ||
| """ | ||
| tours = inject.get_table('tours').to_frame() | ||
| expressions.assign_columns( | ||
| df=tours, | ||
| model_settings=model_settings.get('annotate_tours'), | ||
| trace_label=tracing.extend_trace_label(trace_label, 'annotate_tours')) | ||
| pipeline.replace_table("tours", tours) | ||
|
|
||
|
|
||
| def get_skim_dict(network_los, choosers): | ||
| """ | ||
| Returns a dictionary of skim wrappers to use in expression writing. | ||
|
|
||
| Skims have origin as home_zone_id and destination as the tour destination. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| network_los : activitysim.core.los.Network_LOS object | ||
| choosers : pd.DataFrame | ||
|
|
||
| Returns | ||
| ------- | ||
| skims : dict | ||
| index is skim wrapper name, value is the skim wrapper | ||
| """ | ||
| skim_dict = network_los.get_default_skim_dict() | ||
| orig_col_name = 'home_zone_id' | ||
| dest_col_name = 'destination' | ||
|
|
||
| out_time_col_name = 'start' | ||
| in_time_col_name = 'end' | ||
| odt_skim_stack_wrapper = skim_dict.wrap_3d(orig_key=orig_col_name, dest_key=dest_col_name, | ||
| dim3_key='out_period') | ||
| dot_skim_stack_wrapper = skim_dict.wrap_3d(orig_key=dest_col_name, dest_key=orig_col_name, | ||
| dim3_key='in_period') | ||
|
|
||
| choosers['in_period'] = network_los.skim_time_period_label(choosers[in_time_col_name]) | ||
| choosers['out_period'] = network_los.skim_time_period_label(choosers[out_time_col_name]) | ||
|
|
||
| skims = { | ||
| "odt_skims": odt_skim_stack_wrapper.set_df(choosers), | ||
| "dot_skims": dot_skim_stack_wrapper.set_df(choosers), | ||
| } | ||
| return skims | ||
|
|
||
|
|
||
| @inject.step() | ||
| def vehicle_allocation( | ||
| persons, | ||
| households, | ||
| vehicles, | ||
| tours, | ||
| tours_merged, | ||
| network_los, | ||
| chunk_size, | ||
| trace_hh_id): | ||
| """Selects a vehicle for each occupancy level for each tour. | ||
|
|
||
| Alternatives consist of the up to the number of household vehicles plus one | ||
| option for non-household vehicles. | ||
|
|
||
| The model will be run once for each tour occupancy defined in the model yaml. | ||
| Output tour table will columns added for each occupancy level. | ||
|
|
||
| The user may also augment the `tours` tables with new vehicle | ||
| type-based fields specified via the annotate_tours option. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| persons : orca.DataFrameWrapper | ||
| households : orca.DataFrameWrapper | ||
| vehicles : orca.DataFrameWrapper | ||
| vehicles_merged : orca.DataFrameWrapper | ||
| tours : orca.DataFrameWrapper | ||
| tours_merged : orca.DataFrameWrapper | ||
| chunk_size : orca.injectable | ||
| trace_hh_id : orca.injectable | ||
| """ | ||
| trace_label = 'vehicle_allocation' | ||
| model_settings_file_name = 'vehicle_allocation.yaml' | ||
| model_settings = config.read_model_settings(model_settings_file_name) | ||
|
|
||
| logsum_column_name = model_settings.get('MODE_CHOICE_LOGSUM_COLUMN_NAME') | ||
|
|
||
| estimator = estimation.manager.begin_estimation('vehicle_allocation') | ||
|
|
||
| model_spec_raw = simulate.read_model_spec(file_name=model_settings['SPEC']) | ||
| coefficients_df = simulate.read_model_coefficients(model_settings) | ||
| model_spec = simulate.eval_coefficients(model_spec_raw, coefficients_df, estimator) | ||
|
|
||
| nest_spec = config.get_logit_model_settings(model_settings) | ||
| constants = config.get_model_constants(model_settings) | ||
|
|
||
| locals_dict = {} | ||
| locals_dict.update(constants) | ||
| locals_dict.update(coefficients_df) | ||
|
|
||
| # ------ constructing alternatives from model spec and joining to choosers | ||
| vehicles_wide = vehicles.to_frame().pivot_table( | ||
| index='household_id', columns='vehicle_num', | ||
| values='vehicle_type', aggfunc=lambda x: ''.join(x)) | ||
|
|
||
| alts_from_spec = model_spec.columns | ||
| # renaming vehicle numbers to alternative names in spec | ||
| vehicle_alt_columns_dict = {} | ||
| for veh_num in range(1, len(alts_from_spec)): | ||
| vehicle_alt_columns_dict[veh_num] = alts_from_spec[veh_num-1] | ||
| vehicles_wide.rename(columns=vehicle_alt_columns_dict, inplace=True) | ||
|
|
||
| # if the number of vehicles is less than the alternatives, fill with NA | ||
| # e.g. all households only have 1 or 2 vehicles because of small sample size, | ||
| # still need columns for alternatives 3 and 4 | ||
| for veh_num, col_name in vehicle_alt_columns_dict.items(): | ||
| if col_name not in vehicles_wide.columns: | ||
| vehicles_wide[col_name] = '' | ||
|
|
||
| # last entry in spec is the non-hh-veh option | ||
| assert alts_from_spec[-1] == 'non_hh_veh', "Last option in spec needs to be non_hh_veh" | ||
| vehicles_wide[alts_from_spec[-1]] = '' | ||
|
|
||
| # merging vehicle alternatives to choosers | ||
| choosers = tours_merged.to_frame().reset_index() | ||
| choosers = pd.merge(choosers, vehicles_wide, how='left', on='household_id') | ||
| choosers.set_index('tour_id', inplace=True) | ||
|
|
||
| # ----- setup skim keys | ||
| skims = get_skim_dict(network_los, choosers) | ||
| locals_dict.update(skims) | ||
|
|
||
| # ------ preprocessor | ||
| preprocessor_settings = model_settings.get('preprocessor', None) | ||
| if preprocessor_settings: | ||
| expressions.assign_columns( | ||
| df=choosers, | ||
| model_settings=preprocessor_settings, | ||
| locals_dict=locals_dict, | ||
| trace_label=trace_label) | ||
|
|
||
| logger.info("Running %s with %d tours", trace_label, len(choosers)) | ||
|
|
||
| if estimator: | ||
| estimator.write_model_settings(model_settings, model_settings_file_name) | ||
| estimator.write_spec(model_settings) | ||
| estimator.write_coefficients(coefficients_df, model_settings) | ||
| estimator.write_choosers(choosers) | ||
|
|
||
| tours = tours.to_frame() | ||
|
|
||
| # ------ running for each occupancy level selected | ||
| tours_veh_occup_cols = [] | ||
| for occup in model_settings.get('OCCUPANCY_LEVELS', [1]): | ||
| logger.info("Running for occupancy = %d", occup) | ||
| # setting occup for access in spec expressions | ||
| locals_dict.update({'occup': occup}) | ||
|
|
||
| choices = simulate.simple_simulate( | ||
| choosers=choosers, | ||
| spec=model_spec, | ||
| nest_spec=nest_spec, | ||
| skims=skims, | ||
| locals_d=locals_dict, | ||
| chunk_size=chunk_size, | ||
| trace_label=trace_label, | ||
| trace_choice_name='vehicle_allocation', | ||
| estimator=estimator) | ||
|
|
||
| # matching alt names to choices | ||
| choices = choices.map(dict(enumerate(alts_from_spec))).to_frame() | ||
| choices.columns = ['alt_choice'] | ||
|
|
||
| # last alternative is the non-household vehicle option | ||
| for alt in alts_from_spec[:-1]: | ||
| choices.loc[choices['alt_choice'] == alt, 'choice'] = \ | ||
| choosers.loc[choices['alt_choice'] == alt, alt] | ||
| choices.loc[choices['alt_choice'] == alts_from_spec[-1], 'choice'] = alts_from_spec[-1] | ||
|
|
||
| # creating a column for choice of each occupancy level | ||
| tours_veh_occup_col = f'vehicle_occup_{occup}' | ||
| tours[tours_veh_occup_col] = choices['choice'] | ||
| tours_veh_occup_cols.append(tours_veh_occup_col) | ||
|
|
||
| if estimator: | ||
| estimator.write_choices(choices) | ||
| choices = estimator.get_survey_values(choices, 'households', 'vehicle_allocation') | ||
| estimator.write_override_choices(choices) | ||
| estimator.end_estimation() | ||
|
|
||
| pipeline.replace_table("tours", tours) | ||
|
|
||
| tracing.print_summary('vehicle_allocation', tours[tours_veh_occup_cols], value_counts=True) | ||
|
|
||
| annotate_settings = model_settings.get('annotate_tours', None) | ||
| if annotate_settings: | ||
| annotate_vehicle_allocation(model_settings, trace_label) | ||
|
|
||
| if trace_hh_id: | ||
| tracing.trace_df(tours, | ||
| label='vehicle_allocation', | ||
| warn_if_empty=True) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.