Skip to content

Commit dc1a1c5

Browse files
Updated auto sufficiency to be based on number of licensed drivers in the household
1 parent 4c8fded commit dc1a1c5

6 files changed

Lines changed: 56 additions & 17 deletions

File tree

dashboard/pages/tour_summaries/tour_mode.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ def build_page(self) -> pn.viewable.Viewable:
172172
**Auto sufficiency definitions**
173173
174174
- **Zero Auto**: household has no vehicles.
175-
- **Auto Deficient**: household has fewer vehicles than workers.
176-
- **Auto Sufficient**: household has at least as many vehicles as workers.
175+
- **Auto Deficient**: household has fewer vehicles than licensed drivers.
176+
- **Auto Sufficient**: household has at least as many vehicles as licensed drivers.
177177
"""
178178
),
179179
self._mode_section,

processor/prepare/enrichment/finalize.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def _cast_households(hh: pl.DataFrame) -> pl.DataFrame:
1919
"HHVEH": pl.Int32,
2020
"HHSIZE": pl.Int32,
2121
"WORKERS": pl.Int32,
22+
"LICENSEDDRIVERS": pl.Int32,
2223
"ADULTS": pl.Int32,
2324
"HGEO": pl.Utf8,
2425
},
@@ -62,6 +63,7 @@ def _cast_tours(tours: pl.DataFrame) -> pl.DataFrame:
6263
"SKIMDIST": pl.Float64,
6364
"NUMBER_HH": pl.Int32,
6465
"AUTOSUFF": pl.Int32,
66+
"LICENSEDDRIVERS": pl.Int32,
6567
"finalweight": pl.Float64,
6668
},
6769
)
@@ -89,6 +91,7 @@ def _cast_trips(trips: pl.DataFrame) -> pl.DataFrame:
8991
"inbound": pl.Int32,
9092
"trip_num": pl.Int32,
9193
"AUTOSUFF": pl.Int32,
94+
"LICENSEDDRIVERS": pl.Int32,
9295
"num_participants": pl.Int32,
9396
"finalweight": pl.Float64,
9497
},

processor/prepare/enrichment/households_persons.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@
1313
LOGGER = get_logger("processor.prepare")
1414

1515

16+
def _licensed_driver_expr(column_name: str = "has_license") -> pl.Expr:
17+
return (
18+
pl.col(column_name)
19+
.cast(pl.Utf8)
20+
.str.to_lowercase()
21+
.is_in(["true", "1", "yes", "licensed"])
22+
)
23+
24+
1625
def _enrich_households(
1726
state: _PrepareState, config: Config, zone_context: _ZoneContext
1827
) -> None:
@@ -142,6 +151,24 @@ def _enrich_persons(
142151
.alias("imf_choice")
143152
)
144153

154+
if {
155+
"household_id",
156+
"has_license",
157+
}.issubset(state.per.columns) and "household_id" in state.hh.columns:
158+
licensed_drivers = (
159+
state.per.filter(
160+
pl.col("household_id").is_not_null() & pl.col("has_license").is_not_null()
161+
)
162+
.group_by("household_id")
163+
.agg(
164+
_licensed_driver_expr().sum().cast(pl.Int32).alias("LICENSEDDRIVERS")
165+
)
166+
)
167+
state.hh = (
168+
state.hh.join(licensed_drivers, on="household_id", how="left")
169+
.with_columns(pl.col("LICENSEDDRIVERS").fill_null(0).cast(pl.Int32))
170+
)
171+
145172

146173
def _enrich_households_and_persons(
147174
state: _PrepareState, config: Config, zone_context: _ZoneContext

processor/prepare/enrichment/tours.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def _enrich_tours(
1717
) -> _PrepareState:
1818
hh_for_tours = [
1919
column
20-
for column in ["household_id", "HHVEH", "WORKERS", "ADULTS"]
20+
for column in ["household_id", "HHVEH", "WORKERS", "LICENSEDDRIVERS", "ADULTS"]
2121
if column in state.hh.columns
2222
]
2323
if "household_id" in state.tours.columns and "household_id" in hh_for_tours:
@@ -27,13 +27,19 @@ def _enrich_tours(
2727
how="left",
2828
)
2929

30-
if "HHVEH" in state.tours.columns and "WORKERS" in state.tours.columns:
30+
if "HHVEH" in state.tours.columns and "LICENSEDDRIVERS" in state.tours.columns:
3131
state.tours = state.tours.with_columns(
3232
pl.when(pl.col("HHVEH") == 0)
3333
.then(0)
34-
.when((pl.col("HHVEH") > 0) & (pl.col("HHVEH") < pl.col("WORKERS")))
34+
.when(
35+
(pl.col("HHVEH") > 0)
36+
& (pl.col("HHVEH") < pl.col("LICENSEDDRIVERS"))
37+
)
3538
.then(1)
36-
.when((pl.col("HHVEH") > 0) & (pl.col("HHVEH") >= pl.col("WORKERS")))
39+
.when(
40+
(pl.col("HHVEH") > 0)
41+
& (pl.col("HHVEH") >= pl.col("LICENSEDDRIVERS"))
42+
)
3743
.then(2)
3844
.otherwise(0)
3945
.alias("AUTOSUFF")

processor/prepare/enrichment/trips.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def _enrich_trips(
5454
if "HHVEH" not in state.trips.columns:
5555
hh_trip_join_cols = [
5656
column
57-
for column in ["household_id", "HHVEH", "WORKERS"]
57+
for column in ["household_id", "HHVEH", "WORKERS", "LICENSEDDRIVERS"]
5858
if column in state.hh.columns
5959
]
6060
if (
@@ -69,14 +69,20 @@ def _enrich_trips(
6969
if (
7070
"AUTOSUFF" not in state.trips.columns
7171
and "HHVEH" in state.trips.columns
72-
and "WORKERS" in state.trips.columns
72+
and "LICENSEDDRIVERS" in state.trips.columns
7373
):
7474
state.trips = state.trips.with_columns(
7575
pl.when(pl.col("HHVEH") == 0)
7676
.then(0)
77-
.when((pl.col("HHVEH") > 0) & (pl.col("HHVEH") < pl.col("WORKERS")))
77+
.when(
78+
(pl.col("HHVEH") > 0)
79+
& (pl.col("HHVEH") < pl.col("LICENSEDDRIVERS"))
80+
)
7881
.then(1)
79-
.when((pl.col("HHVEH") > 0) & (pl.col("HHVEH") >= pl.col("WORKERS")))
82+
.when(
83+
(pl.col("HHVEH") > 0)
84+
& (pl.col("HHVEH") >= pl.col("LICENSEDDRIVERS"))
85+
)
8086
.then(2)
8187
.otherwise(0)
8288
.alias("AUTOSUFF")

processor/summarize/summaries/tour.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ def allocated_vehicle_body(rd: RunData, config: Config) -> pl.DataFrame:
219219
"tour_count_auto_sufficient": pl.Float64,
220220
"tour_count_all_households": pl.Float64,
221221
},
222-
required_columns={"tours": ("tour_mode", "tour_purpose", "finalweight")},
222+
required_columns={"tours": ("tour_mode", "tour_purpose", "finalweight", "AUTOSUFF")},
223223
)
224224
def tour_mode(rd: RunData, config: Config) -> pl.DataFrame:
225225
"""Tour mode by auto sufficiency level and total, by tour purpose/category.
@@ -229,7 +229,8 @@ def tour_mode(rd: RunData, config: Config) -> pl.DataFrame:
229229
tour_count_zero_auto, tour_count_auto_deficient,
230230
tour_count_auto_sufficient, tour_count_all_households.
231231
"""
232-
if "tour_mode" not in rd.tours.columns:
232+
required = {"tour_mode", "tour_purpose", "finalweight", "AUTOSUFF"}
233+
if not required.issubset(set(rd.tours.columns)):
233234
return empty_summary_frame(tour_mode)
234235

235236
indiv = (
@@ -280,11 +281,7 @@ def tour_mode(rd: RunData, config: Config) -> pl.DataFrame:
280281
wgt_col = "wgt" if "wgt" in df.columns else "finalweight"
281282

282283
for as_val in range(3):
283-
as_filter = (
284-
(pl.col("AUTOSUFF") == as_val)
285-
if "AUTOSUFF" in df.columns
286-
else pl.lit(True)
287-
)
284+
as_filter = pl.col("AUTOSUFF") == as_val
288285

289286
sub = df.filter(purpose_filter & as_filter)
290287
counts = sub.group_by("tour_mode").agg(pl.col(wgt_col).sum().alias("n"))

0 commit comments

Comments
 (0)