-
Notifications
You must be signed in to change notification settings - Fork 1
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
Revise travel day #82
Changes from all commits
84a9273
a588c67
9fa6b0f
40d2e2f
7411e46
3e521ea
5b6cfbb
489e085
0e06e29
9c0003a
6164a28
0cea61f
88f4911
e0fc2f9
ed45b92
ce5a261
ced648d
5f17c56
4b6db8c
1f5e0b9
4ce4b1a
46946d1
4301493
be2eb6b
748260a
5105dab
32dfe63
6ebd5be
1dd281b
a07c035
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
[parameters] | ||
seed = 0 | ||
# this is used to query poi data from osm and to load in SPC data | ||
region = "leeds" | ||
# how many people from the SPC do we want to run the model for? Comment out if you want to run the analysis on the entire SPC populaiton | ||
number_of_households = 25000 | ||
# "OA21CD": OA level, "MSOA11CD": MSOA level | ||
zone_id = "MSOA21CD" | ||
# Only set to true if you have travel time matrix at the level specified in boundary_geography | ||
travel_times = false | ||
boundary_geography = "MSOA" | ||
# NTS years to use | ||
nts_years = [2019, 2021, 2022] | ||
# NTS regions to use | ||
nts_regions = [ | ||
'Yorkshire and the Humber', | ||
'North West', | ||
'North East', | ||
'East Midlands', | ||
'West Midlands', | ||
'East of England', | ||
'South East', | ||
'South West'] | ||
# nts day of the week to use | ||
# 1: Monday, 2: Tuesday, 3: Wednesday, 4: Thursday, 5: Friday, 6: Saturday, 7: Sunday | ||
nts_day_of_week = 3 | ||
# what crs do we want the output to be in? (just add the number, e.g. 3857) | ||
output_crs = 3857 | ||
|
||
[matching] | ||
# for optional and required columns, see the [iterative_match_categorical](https://github.com/Urban-Analytics-Technology-Platform/acbm/blob/ca181c54d7484ebe44706ff4b43c26286b22aceb/src/acbm/matching.py#L110) function | ||
# Do not add any column not listed below. You can only move a column from optional to require (or vise versa) | ||
required_columns = [ | ||
"number_adults", | ||
"number_children", | ||
"num_pension_age", | ||
] | ||
optional_columns = [ | ||
"number_cars", | ||
"rural_urban_2_categories", | ||
"employment_status", | ||
"tenure_status", | ||
] | ||
# What is the maximum number of NTS matches we want for each SPC household? | ||
n_matches = 10 | ||
|
||
[feasible_assignment] | ||
# detour factor when converting euclidian distance to actual travel distance | ||
detour_factor = 1.56 | ||
# decay rate when converting euclidian to travel distance (0.0001 is a good value) | ||
# actual_distance = distance * (1 + ((detour_factor - 1) * np.exp(-decay_rate * distance))) | ||
decay_rate = 0.0001 | ||
|
||
[work_assignment] | ||
commute_level = "MSOA" | ||
# if true, optimization problem will try to minimize percentage difference at OD level (not absolute numbers). Recommended to set it to true | ||
use_percentages = true | ||
# weights to add for each objective in the optimization problem | ||
weight_max_dev = 0.2 | ||
weight_total_dev = 0.8 | ||
# maximum number of feasible zones to include in the optimization problem (less zones makes problem smaller - so faster, but at the cost of a better solution) | ||
max_zones = 10 | ||
|
||
[postprocessing] | ||
pam_jitter = 30 | ||
pam_min_duration = 10 | ||
# for get_pt_subscription: everyone above this age has a subscription (pensioners get free travel) | ||
# TODO: more sophisticated approach | ||
pt_subscription_age = 66 | ||
# to define if a person is a student: | ||
# eveyone below this age is a student | ||
student_age_base = 16 | ||
# everyone below this age that has at least one "education" activity is a student | ||
student_age_upper = 30 | ||
# eveyone who uses one of the modes below is classified as a passenger (isPassenger = True) | ||
modes_passenger = ['car_passenger', 'taxi'] | ||
# yearly state pension: for getting hhlIncome of pensioners | ||
state_pension = 11502 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ | |
from acbm.assigning.utils import cols_for_assignment_all | ||
from acbm.cli import acbm_cli | ||
from acbm.config import load_and_setup_config | ||
from acbm.matching import MatcherExact, match_individuals | ||
from acbm.matching import MatcherExact, match_individuals, match_remaining_individuals | ||
from acbm.preprocessing import ( | ||
count_per_group, | ||
nts_filter_by_region, | ||
|
@@ -16,6 +16,10 @@ | |
transform_by_group, | ||
truncate_values, | ||
) | ||
from acbm.utils import ( | ||
households_with_common_travel_days, | ||
households_with_travel_days_in_nts_weeks, | ||
) | ||
|
||
|
||
@acbm_cli | ||
|
@@ -222,23 +226,48 @@ def get_interim_path( | |
|
||
logger.info("Filtering NTS data by specified year(s)") | ||
|
||
logger.info(f"Total NTS households: {nts_households.shape[0]:,.0f}") | ||
years = config.parameters.nts_years | ||
|
||
nts_individuals = nts_filter_by_year(nts_individuals, psu, years) | ||
nts_households = nts_filter_by_year(nts_households, psu, years) | ||
nts_trips = nts_filter_by_year(nts_trips, psu, years) | ||
|
||
logger.info( | ||
f"Total NTS households (after year filtering): {nts_households.shape[0]:,.0f}" | ||
) | ||
# #### Filter by geography | ||
# | ||
|
||
regions = config.parameters.nts_regions | ||
|
||
nts_individuals = nts_filter_by_region(nts_individuals, psu, regions) | ||
nts_households = nts_filter_by_region(nts_households, psu, regions) | ||
nts_trips = nts_filter_by_region(nts_trips, psu, regions) | ||
|
||
# Create dictionaries of key value pairs | ||
logger.info( | ||
f"Total NTS households (after region filtering): {nts_households.shape[0]:,.0f}" | ||
) | ||
|
||
# Ensure that the households have at least one day in `nts_days_of_week` that | ||
# all household members have trips for | ||
if config.parameters.common_household_day: | ||
hids = households_with_common_travel_days( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gets the subset of households where all individuals have a common |
||
nts_trips, config.parameters.nts_days_of_week | ||
) | ||
else: | ||
hids = households_with_travel_days_in_nts_weeks( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gets the subset of households where all individuals have any |
||
nts_trips, config.parameters.nts_days_of_week | ||
) | ||
|
||
# Subset individuals and households given filtering of trips | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Subset to the households subset above before matching to ensure matches have required |
||
nts_trips = nts_trips[ | ||
nts_trips["HouseholdID"].isin(hids) | ||
& nts_trips["TravDay"].isin(config.parameters.nts_days_of_week) | ||
] | ||
nts_individuals = nts_individuals[nts_individuals["HouseholdID"].isin(hids)] | ||
nts_households = nts_households[nts_households["HouseholdID"].isin(hids)] | ||
|
||
# Create dictionaries of key value pairs | ||
""" | ||
guide to the dictionaries: | ||
|
||
|
@@ -924,6 +953,19 @@ def get_interim_path( | |
show_progress=True, | ||
) | ||
|
||
# match remaining individuals | ||
remaining_ids = spc_edited.loc[ | ||
~spc_edited.index.isin(matches_ind.keys()), "id" | ||
].to_list() | ||
matches_remaining_ind = match_remaining_individuals( | ||
df1=spc_edited, | ||
df2=nts_individuals, | ||
matching_columns=["age_group", "sex"], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could update the matching_columns here to enable more precision when not using households: e.g. for employment status and urban rural classification. |
||
remaining_ids=remaining_ids, | ||
show_progress=True, | ||
) | ||
matches_ind.update(matches_remaining_ind) | ||
|
||
Comment on lines
+956
to
+968
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add matching for any remaining individuals that were part of unmatched households. It might be worth considering if this should be more configurable. |
||
# save random sample | ||
with open( | ||
get_interim_path("matches_ind_level_categorical_random_sample.pkl"), "wb" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
from acbm.assigning.utils import ( | ||
activity_chains_for_assignment, | ||
get_activities_per_zone, | ||
get_chosen_day, | ||
intrazone_time, | ||
replace_intrazonal_travel_time, | ||
zones_to_time_matrix, | ||
|
@@ -28,11 +29,15 @@ def main(config_file): | |
activity_chains = activity_chains_for_assignment(config) | ||
logger.info("Activity chains loaded") | ||
|
||
# Filter to a specific day of the week | ||
logger.info("Filtering activity chains to a specific day of the week") | ||
activity_chains = activity_chains[ | ||
activity_chains["TravDay"] == config.parameters.nts_day_of_week | ||
] | ||
|
||
# Generate random sample of days by household | ||
get_chosen_day(config).to_parquet( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Get a chosen day for each individual to represent a "sample" day given the configured days of the week and whether the household is configured to share a common day. |
||
config.output_path / "interim" / "assigning" / "chosen_trav_day.parquet" | ||
) | ||
|
||
# Filter to chosen day | ||
activity_chains = activity_chains_for_assignment(config, subset_to_chosen_day=True) | ||
|
||
# --- Study area boundaries | ||
|
||
|
@@ -74,7 +79,11 @@ def main(config_file): | |
logger.info("Creating estimated travel times matrix") | ||
# Create a new travel time matrix based on distances between zones | ||
travel_time_estimates = zones_to_time_matrix( | ||
zones=boundaries, id_col=config.zone_id, time_units="m" | ||
zones=boundaries, | ||
id_col=config.zone_id, | ||
time_units="m", | ||
detour_factor=config.feasible_assignment.detour_factor, | ||
decay_rate=config.feasible_assignment.decay_rate, | ||
) | ||
logger.info("Travel time estimates created") | ||
|
||
|
@@ -203,6 +212,8 @@ def main(config_file): | |
time_tolerance=config.parameters.tolerance_edu | ||
if config.parameters.tolerance_edu is not None | ||
else 0.3, | ||
detour_factor=config.feasible_assignment.detour_factor, | ||
decay_rate=config.feasible_assignment.decay_rate, | ||
) | ||
|
||
logger.info("Saving feasible zones for education activities") | ||
|
@@ -230,6 +241,8 @@ def main(config_file): | |
time_tolerance=config.parameters.tolerance_work | ||
if config.parameters.tolerance_work is not None | ||
else 0.3, | ||
detour_factor=config.feasible_assignment.detour_factor, | ||
decay_rate=config.feasible_assignment.decay_rate, | ||
) | ||
|
||
logger.info("Saving feasible zones for work activities") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new parameter boolean
common_household_day
determines whether all individuals of the household need to have aTravDay
in common.