Skip to content

Commit 131f09a

Browse files
Copilotjpn--
andauthored
Deprecate SIMULATE_CHOOSER_COLUMNS and LOGSUM_CHOOSER_COLUMNS settings (#1094)
* Initial plan * Deprecate SIMULATE_CHOOSER_COLUMNS and LOGSUM_CHOOSER_COLUMNS settings * Drop unused columns in interaction_sample even when tracing * Fix chooser column deprecation regressions --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Jeff Newman <jeff@driftless.xyz>
1 parent 2b73d5a commit 131f09a

70 files changed

Lines changed: 487 additions & 787 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

activitysim/abm/models/location_choice.py

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,10 @@ def location_sample(
242242
chunk_tag,
243243
trace_label,
244244
):
245-
# FIXME - MEMORY HACK - only include columns actually used in spec
246-
chooser_columns = model_settings.SIMULATE_CHOOSER_COLUMNS
247-
# Drop this when PR #1017 is merged
248-
if ("household_id" not in chooser_columns) and (
249-
"household_id" in persons_merged.columns
250-
):
251-
chooser_columns = chooser_columns + ["household_id"]
252-
choosers = persons_merged[chooser_columns]
245+
# The former column selection returned an independent frame. Preserve that
246+
# isolation so component preprocessors cannot leak annotations into the
247+
# shared persons table or into later location-choice segments.
248+
choosers = persons_merged.copy()
253249

254250
# create wrapper with keys for this lookup - in this case there is a home_zone_id in the choosers
255251
# and a zone_id in the alternatives which get merged during interaction
@@ -441,17 +437,8 @@ def location_presample(
441437
HOME_TAZ in persons_merged
442438
) # 'TAZ' should already be in persons_merged from land_use
443439

444-
# FIXME - MEMORY HACK - only include columns actually used in spec
445-
# FIXME we don't actually require that land_use provide a TAZ crosswalk
446-
# FIXME maybe we should add it for multi-zone (from maz_taz) if missing?
447-
chooser_columns = model_settings.SIMULATE_CHOOSER_COLUMNS
448-
chooser_columns = [HOME_TAZ if c == HOME_MAZ else c for c in chooser_columns]
449-
# Drop this when PR #1017 is merged
450-
if ("household_id" not in chooser_columns) and (
451-
"household_id" in persons_merged.columns
452-
):
453-
chooser_columns = chooser_columns + ["household_id"]
454-
choosers = persons_merged[chooser_columns]
440+
# Keep chooser annotations local to this model segment.
441+
choosers = persons_merged.copy()
455442

456443
# create wrapper with keys for this lookup - in this case there is a HOME_TAZ in the choosers
457444
# and a DEST_TAZ in the alternatives which get merged during interaction
@@ -627,11 +614,6 @@ def run_location_logsums(
627614
mandatory=False,
628615
)
629616

630-
# FIXME - MEMORY HACK - only include columns actually used in spec
631-
persons_merged_df = logsum.filter_chooser_columns(
632-
persons_merged_df, logsum_settings, model_settings
633-
)
634-
635617
logger.info(f"Running {trace_label} with {len(location_sample_df.index)} rows")
636618

637619
choosers = location_sample_df.join(persons_merged_df, how="left")
@@ -691,14 +673,9 @@ def run_location_simulate(
691673
"""
692674
assert not persons_merged.empty
693675

694-
# FIXME - MEMORY HACK - only include columns actually used in spec
695-
chooser_columns = model_settings.SIMULATE_CHOOSER_COLUMNS
696-
# Drop this when PR #1017 is merged
697-
if ("household_id" not in chooser_columns) and (
698-
"household_id" in persons_merged.columns
699-
):
700-
chooser_columns = chooser_columns + ["household_id"]
701-
choosers = persons_merged[chooser_columns]
676+
# Preprocessors annotate choosers in place. Use a copy so those temporary
677+
# columns do not affect subsequent segments that share persons_merged.
678+
choosers = persons_merged.copy()
702679

703680
alt_dest_col_name = model_settings.ALT_DEST_COL_NAME
704681

activitysim/abm/models/school_escorting.py

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
from __future__ import annotations
44

55
import logging
6+
import warnings
67
from typing import Any, Literal
78

89
import numpy as np
910
import pandas as pd
11+
from pydantic import field_validator
1012

1113
from activitysim.abm.models.util import school_escort_tours_trips
1214
from activitysim.core import (
@@ -391,7 +393,26 @@ class SchoolEscortSettings(BaseLogitComponentSettings, extra="forbid"):
391393
GENDER_WEIGHT: float = 10.0
392394
AGE_WEIGHT: float = 1.0
393395

394-
SIMULATE_CHOOSER_COLUMNS: list[str] | None = None
396+
SIMULATE_CHOOSER_COLUMNS: Any | None = None
397+
"""Was used to help reduce the memory needed for the model.
398+
399+
This setting is now obsolete and does nothing. Its functionality has been
400+
replaced by :func:`activitysim.core.util.drop_unused_columns`.
401+
402+
.. deprecated:: 1.6
403+
"""
404+
405+
@field_validator("SIMULATE_CHOOSER_COLUMNS", mode="before")
406+
@classmethod
407+
def _deprecate_simulate_chooser_columns(cls, value):
408+
if value is not None:
409+
warnings.warn(
410+
"SIMULATE_CHOOSER_COLUMNS is deprecated and no longer used, "
411+
"unused columns are now dropped automatically",
412+
DeprecationWarning,
413+
stacklevel=2,
414+
)
415+
return None
395416

396417
SPEC: None = None
397418
"""The school escort model does not use this setting."""
@@ -521,17 +542,6 @@ def school_escorting(
521542
# else:
522543
# locals_dict.pop("_sharrow_skip", None)
523544

524-
# reduce memory by limiting columns if selected columns are supplied
525-
chooser_columns = model_settings.SIMULATE_CHOOSER_COLUMNS
526-
if chooser_columns is not None:
527-
# Drop this when PR #1017 is merged
528-
if ("household_id" not in chooser_columns) and (
529-
"household_id" in choosers.columns
530-
):
531-
chooser_columns = chooser_columns + ["household_id"]
532-
chooser_columns = chooser_columns + participant_columns
533-
choosers = choosers[chooser_columns]
534-
535545
# add previous data to stage
536546
if stage_num >= 1:
537547
choosers = add_prev_choices_to_choosers(
@@ -622,10 +632,14 @@ def school_escorting(
622632
)
623633

624634
if stage_num >= 1:
625-
choosers["alt"] = choices
626-
choosers = choosers.join(alts, how="left", on="alt")
635+
# The raw alternative columns are only needed to construct bundle
636+
# records. Do not retain them on the chooser state: the final
637+
# stage would otherwise try to join the same columns a second time.
638+
bundle_choosers = choosers.assign(alt=choices).join(
639+
alts, how="left", on="alt"
640+
)
627641
bundles = create_school_escorting_bundles_table(
628-
choosers[choosers["alt"] > 1], tours, stage
642+
bundle_choosers[bundle_choosers["alt"] > 1], tours, stage
629643
)
630644
escort_bundles.append(bundles)
631645

activitysim/abm/models/util/logsums.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import pandas as pd
88

99
from activitysim.core import config, expressions, los, simulate, tracing, workflow
10-
from activitysim.core.configuration import PydanticBase
1110
from activitysim.core.configuration.logit import (
1211
TourLocationComponentSettings,
1312
TourModeComponentSettings,
@@ -16,41 +15,6 @@
1615
logger = logging.getLogger(__name__)
1716

1817

19-
def filter_chooser_columns(
20-
choosers, logsum_settings: dict | PydanticBase, model_settings: dict | PydanticBase
21-
):
22-
try:
23-
chooser_columns = logsum_settings.LOGSUM_CHOOSER_COLUMNS
24-
except AttributeError:
25-
chooser_columns = logsum_settings.get("LOGSUM_CHOOSER_COLUMNS", [])
26-
27-
if (
28-
isinstance(model_settings, dict)
29-
and "CHOOSER_ORIG_COL_NAME" in model_settings
30-
and model_settings["CHOOSER_ORIG_COL_NAME"] not in chooser_columns
31-
):
32-
chooser_columns.append(model_settings["CHOOSER_ORIG_COL_NAME"])
33-
if (
34-
isinstance(model_settings, PydanticBase)
35-
and hasattr(model_settings, "CHOOSER_ORIG_COL_NAME")
36-
and model_settings.CHOOSER_ORIG_COL_NAME
37-
and model_settings.CHOOSER_ORIG_COL_NAME not in chooser_columns
38-
):
39-
chooser_columns.append(model_settings.CHOOSER_ORIG_COL_NAME)
40-
41-
missing_columns = [c for c in chooser_columns if c not in choosers]
42-
if missing_columns:
43-
logger.debug(
44-
"logsum.filter_chooser_columns missing_columns %s" % missing_columns
45-
)
46-
47-
# ignore any columns not appearing in choosers df
48-
chooser_columns = [c for c in chooser_columns if c in choosers]
49-
50-
choosers = choosers[chooser_columns]
51-
return choosers
52-
53-
5418
def compute_location_choice_logsums(
5519
state: workflow.State,
5620
choosers: pd.DataFrame,

activitysim/abm/models/util/tour_destination.py

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,10 @@ def destination_presample(
637637

638638
orig_maz = model_settings.CHOOSER_ORIG_COL_NAME
639639
assert orig_maz in choosers
640-
if ORIG_TAZ not in choosers:
641-
choosers[ORIG_TAZ] = network_los.map_maz_to_taz(choosers[orig_maz])
640+
# This is the TAZ for the configured tour origin. A wider chooser table
641+
# may already contain a same-named home TAZ, which is incorrect for models
642+
# such as at-work subtour destination choice.
643+
choosers[ORIG_TAZ] = network_los.map_maz_to_taz(choosers[orig_maz])
642644

643645
# create wrapper with keys for this lookup - in this case there is a HOME_TAZ in the choosers
644646
# and a DEST_TAZ in the alternatives which get merged during interaction
@@ -691,23 +693,9 @@ def run_destination_sample(
691693
chunk_size,
692694
trace_label,
693695
):
694-
# FIXME - MEMORY HACK - only include columns actually used in spec (omit them pre-merge)
695-
chooser_columns = model_settings.SIMULATE_CHOOSER_COLUMNS
696-
697696
# if special person id is passed
698697
chooser_id_column = model_settings.CHOOSER_ID_COLUMN
699698

700-
# Drop this when PR #1017 is merged
701-
if ("household_id" not in chooser_columns) and (
702-
"household_id" in persons_merged.columns
703-
):
704-
chooser_columns = chooser_columns + ["household_id"]
705-
persons_merged = persons_merged[
706-
[c for c in persons_merged.columns if c in chooser_columns]
707-
]
708-
tours = tours[
709-
[c for c in tours.columns if c in chooser_columns or c == chooser_id_column]
710-
]
711699
choosers = pd.merge(
712700
tours, persons_merged, left_on=chooser_id_column, right_index=True, how="left"
713701
)
@@ -805,11 +793,6 @@ def run_destination_logsums(
805793

806794
chunk_tag = "tour_destination.logsums"
807795

808-
# FIXME - MEMORY HACK - only include columns actually used in spec
809-
persons_merged = logsum.filter_chooser_columns(
810-
persons_merged, logsum_settings, model_settings
811-
)
812-
813796
# merge persons into tours
814797
choosers = pd.merge(
815798
destination_sample,
@@ -872,23 +855,9 @@ def run_destination_simulate(
872855
coefficients_file_name=model_settings.COEFFICIENTS,
873856
)
874857

875-
# FIXME - MEMORY HACK - only include columns actually used in spec (omit them pre-merge)
876-
chooser_columns = model_settings.SIMULATE_CHOOSER_COLUMNS
877-
878858
# if special person id is passed
879859
chooser_id_column = model_settings.CHOOSER_ID_COLUMN
880860

881-
# Drop this when PR #1017 is merged
882-
if ("household_id" not in chooser_columns) and (
883-
"household_id" in persons_merged.columns
884-
):
885-
chooser_columns = chooser_columns + ["household_id"]
886-
persons_merged = persons_merged[
887-
[c for c in persons_merged.columns if c in chooser_columns]
888-
]
889-
tours = tours[
890-
[c for c in tours.columns if c in chooser_columns or c == chooser_id_column]
891-
]
892861
choosers = pd.merge(
893862
tours, persons_merged, left_on=chooser_id_column, right_index=True, how="left"
894863
)

activitysim/abm/models/util/tour_od.py

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -736,13 +736,8 @@ def run_od_sample(
736736
coefficients_file_name=model_settings.COEFFICIENTS,
737737
)
738738

739-
choosers = tours
740-
# FIXME - MEMORY HACK - only include columns actually used in spec
741-
chooser_columns = model_settings.SIMULATE_CHOOSER_COLUMNS
742-
# Drop this when PR #1017 is merged
743-
if ("household_id" not in chooser_columns) and ("household_id" in choosers.columns):
744-
chooser_columns = chooser_columns + ["household_id"]
745-
choosers = choosers[chooser_columns]
739+
# Preserve the independent-frame behavior of the former column subset.
740+
choosers = tours.copy()
746741

747742
# interaction_sample requires that choosers.index.is_monotonic_increasing
748743
if not choosers.index.is_monotonic_increasing:
@@ -820,11 +815,6 @@ def run_od_logsums(
820815
dest_id_col = model_settings.DEST_COL_NAME
821816
tour_od_id_col = get_od_id_col(origin_id_col, dest_id_col)
822817

823-
# FIXME - MEMORY HACK - only include columns actually used in spec
824-
tours_merged_df = logsum.filter_chooser_columns(
825-
tours_merged_df, logsum_settings, model_settings
826-
)
827-
828818
# merge ods into choosers table
829819
choosers = od_sample.join(tours_merged_df, how="left")
830820
choosers[tour_od_id_col] = (
@@ -998,14 +988,9 @@ def run_od_simulate(
998988
)
999989

1000990
# merge persons into tours
1001-
choosers = tours
1002-
1003-
# FIXME - MEMORY HACK - only include columns actually used in spec
1004-
chooser_columns = model_settings.SIMULATE_CHOOSER_COLUMNS
1005-
# Drop this when PR #1017 is merged
1006-
if ("household_id" not in chooser_columns) and ("household_id" in choosers.columns):
1007-
chooser_columns = chooser_columns + ["household_id"]
1008-
choosers = choosers[chooser_columns]
991+
# Preprocessors may annotate choosers in place; keep those columns local to
992+
# this segment instead of mutating the shared tours table.
993+
choosers = tours.copy()
1009994

1010995
# interaction_sample requires that choosers.index.is_monotonic_increasing
1011996
if not choosers.index.is_monotonic_increasing:

activitysim/abm/models/util/tour_scheduling.py

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from activitysim.abm.models.util import vectorize_tour_scheduling as vts
1010
from activitysim.core import config, estimation, expressions, simulate, workflow
1111

12-
from .vectorize_tour_scheduling import TourModeComponentSettings, TourSchedulingSettings
12+
from .vectorize_tour_scheduling import TourSchedulingSettings
1313

1414
logger = logging.getLogger(__name__)
1515

@@ -24,29 +24,9 @@ def run_tour_scheduling(
2424
trace_label: str,
2525
):
2626

27-
if model_settings.LOGSUM_SETTINGS:
28-
logsum_settings = TourModeComponentSettings.read_settings_file(
29-
state.filesystem,
30-
str(model_settings.LOGSUM_SETTINGS),
31-
mandatory=False,
32-
)
33-
logsum_columns = logsum_settings.LOGSUM_CHOOSER_COLUMNS
34-
else:
35-
logsum_columns = []
36-
37-
# - filter chooser columns for both logsums and simulate
38-
model_columns = model_settings.SIMULATE_CHOOSER_COLUMNS
39-
chooser_columns = logsum_columns + [
40-
c for c in model_columns if c not in logsum_columns
41-
]
42-
43-
# Drop this when PR #1017 is merged
44-
if ("household_id" not in chooser_columns) and (
45-
"household_id" in persons_merged.columns
46-
):
47-
chooser_columns = chooser_columns + ["household_id"]
48-
49-
persons_merged = expressions.filter_chooser_columns(persons_merged, chooser_columns)
27+
# The deprecated chooser-column filter returned a new frame. Retain that
28+
# isolation because vectorized scheduling annotates merged chooser data.
29+
persons_merged = persons_merged.copy()
5030

5131
timetable = state.get_injectable("timetable")
5232

activitysim/abm/models/util/vectorize_tour_scheduling.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
from __future__ import annotations
44

55
import logging
6+
import warnings
67
from collections import OrderedDict
78
from pathlib import Path
89
from typing import Any
910

1011
import numpy as np
1112
import pandas as pd
13+
from pydantic import field_validator
1214

1315
from activitysim.abm.models.tour_mode_choice import TourModeComponentSettings
1416
from activitysim.core import chunk, config, expressions, los, simulate
@@ -43,7 +45,26 @@ class TourSchedulingSettings(LogitComponentSettings, extra="forbid"):
4345
it is assumed to be an unsegmented preprocessor. Otherwise, the dict keys
4446
give the segements.
4547
"""
46-
SIMULATE_CHOOSER_COLUMNS: list[str] | None = None
48+
SIMULATE_CHOOSER_COLUMNS: Any | None = None
49+
"""Was used to help reduce the memory needed for the model.
50+
51+
This setting is now obsolete and does nothing. Its functionality has been
52+
replaced by :func:`activitysim.core.util.drop_unused_columns`.
53+
54+
.. deprecated:: 1.6
55+
"""
56+
57+
@field_validator("SIMULATE_CHOOSER_COLUMNS", mode="before")
58+
@classmethod
59+
def _deprecate_simulate_chooser_columns(cls, value):
60+
if value is not None:
61+
warnings.warn(
62+
"SIMULATE_CHOOSER_COLUMNS is deprecated and no longer used, "
63+
"unused columns are now dropped automatically",
64+
DeprecationWarning,
65+
stacklevel=2,
66+
)
67+
return None
4768

4869
SPEC_SEGMENTS: dict[str, LogitComponentSettings] = {}
4970

0 commit comments

Comments
 (0)