ltc-code 0.1.96__tar.gz → 0.1.97__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ltc_code-0.1.96 → ltc_code-0.1.97}/PKG-INFO +1 -1
- {ltc_code-0.1.96 → ltc_code-0.1.97}/pyproject.toml +1 -1
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/june13.py +77 -41
- {ltc_code-0.1.96 → ltc_code-0.1.97}/README.md +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/__init__.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/aspire.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/check_cmo_apps.do +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/christel_house.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/green_dot.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/helpers.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/june2.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/june5.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/june7.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/kipp_nj.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/kipp_tx.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/main.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/mappings.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/may27.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/polars_dates.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/rocketship.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/schema_mapping.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.97}/src/ltc_code/yes_prep.py +0 -0
|
@@ -2,6 +2,13 @@ from typing import Callable, Optional, Sequence, Union
|
|
|
2
2
|
|
|
3
3
|
import polars as pl
|
|
4
4
|
|
|
5
|
+
from typing import Callable, Optional, Sequence, Union
|
|
6
|
+
|
|
7
|
+
import polars as pl
|
|
8
|
+
|
|
9
|
+
Frame =
|
|
10
|
+
Rule = Union[pl.Expr, Callable[[Frame], pl.Expr]]
|
|
11
|
+
|
|
5
12
|
|
|
6
13
|
def impute_offers(
|
|
7
14
|
frame: Union[pl.DataFrame, pl.LazyFrame],
|
|
@@ -13,6 +20,7 @@ def impute_offers(
|
|
|
13
20
|
waitlist_imputation: Optional[Union[pl.Expr, Callable[[Frame], pl.Expr]]] = None,
|
|
14
21
|
enrollment_imputation: Optional[Union[pl.Expr, Callable[[Frame], pl.Expr]]] = None,
|
|
15
22
|
sibling_priority_cols: Optional[Sequence[str]] = None,
|
|
23
|
+
within_cols: Optional[Sequence[str]] = None,
|
|
16
24
|
) -> Union[pl.DataFrame, pl.LazyFrame]:
|
|
17
25
|
"""
|
|
18
26
|
Impute offer indicators in a Polars DataFrame or LazyFrame.
|
|
@@ -28,48 +36,73 @@ def impute_offers(
|
|
|
28
36
|
already had an observed offer are never flagged. Multiple flags may be 1
|
|
29
37
|
for the same row if multiple rules independently imply an offer.
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
frame:
|
|
42
|
+
Polars DataFrame or LazyFrame.
|
|
43
|
+
offer_col:
|
|
44
|
+
Name of the observed offer column. Null is treated as 0.
|
|
45
|
+
lottery_number_col:
|
|
46
|
+
Optional lottery number column.
|
|
47
|
+
waitlist_number_col:
|
|
48
|
+
Optional waitlist number column.
|
|
49
|
+
enrollment_col:
|
|
50
|
+
Optional enrollment indicator column.
|
|
51
|
+
lottery_imputation, waitlist_imputation, enrollment_imputation:
|
|
52
|
+
Optional custom imputation rules. Each may be a Polars expression or a
|
|
53
|
+
callable that accepts ``frame`` and returns a Polars expression.
|
|
54
|
+
sibling_priority_cols:
|
|
55
|
+
Optional columns indicating sibling priority. If supplied, observed
|
|
56
|
+
sibling-priority offers are excluded when computing the default lottery
|
|
57
|
+
cutoff.
|
|
58
|
+
within_cols:
|
|
59
|
+
Optional columns defining the risk set within which lottery and waitlist
|
|
60
|
+
cutoffs are computed. For example:
|
|
61
|
+
|
|
62
|
+
["school_name", "school_year", "entry_grade_clean", "priority_group"]
|
|
63
|
+
|
|
64
|
+
If omitted, cutoffs are computed globally.
|
|
65
|
+
|
|
66
|
+
Default Rules
|
|
67
|
+
-------------
|
|
68
|
+
Lottery:
|
|
69
|
+
Within each ``within_cols`` group, find the highest lottery number among
|
|
70
|
+
observed offers, excluding sibling-priority offers if
|
|
71
|
+
``sibling_priority_cols`` is supplied. Impute offers for originally
|
|
72
|
+
non-offered rows with lottery numbers at or below that cutoff.
|
|
73
|
+
|
|
74
|
+
Enrollment:
|
|
75
|
+
Impute offers for originally non-offered enrolled rows.
|
|
76
|
+
|
|
77
|
+
Waitlist:
|
|
78
|
+
If enrollment information is supplied, first infer offers from
|
|
79
|
+
enrollment, then within each group use the highest waitlist number among
|
|
80
|
+
those enrollment-implied offers as the waitlist cutoff.
|
|
81
|
+
|
|
82
|
+
If enrollment information is not supplied, within each group use the
|
|
83
|
+
highest waitlist number among observed offers as the waitlist cutoff.
|
|
84
|
+
|
|
85
|
+
Then impute offers for originally non-offered rows with waitlist numbers
|
|
86
|
+
at or below that cutoff.
|
|
48
87
|
|
|
49
88
|
Example
|
|
50
89
|
-------
|
|
51
|
-
>>>
|
|
52
|
-
... "offer": [1, 0, 0, None],
|
|
53
|
-
... "lottery_num": [10, 11, 12, 13],
|
|
54
|
-
... "waitlist_num": [None, 1, 2, 3],
|
|
55
|
-
... "enrolled": [0, 0, 1, 0],
|
|
56
|
-
... "sib_1": [0, 0, 0, 0],
|
|
57
|
-
... "sib_2": [0, 0, 0, 0],
|
|
58
|
-
... })
|
|
59
|
-
>>> impute_offers(
|
|
90
|
+
>>> result = impute_offers(
|
|
60
91
|
... df,
|
|
61
92
|
... offer_col="offer",
|
|
62
|
-
... lottery_number_col="
|
|
63
|
-
... waitlist_number_col="
|
|
64
|
-
... enrollment_col="
|
|
65
|
-
... sibling_priority_cols=["
|
|
93
|
+
... lottery_number_col="lottery_number",
|
|
94
|
+
... waitlist_number_col="waitlist_number",
|
|
95
|
+
... enrollment_col="enroll_school_year",
|
|
96
|
+
... sibling_priority_cols=["sibling", "sibling_concur"],
|
|
97
|
+
... within_cols=["school_name", "school_year", "entry_grade_clean", "priority_group"],
|
|
66
98
|
... )
|
|
67
|
-
shape: (4, 9)
|
|
68
|
-
...
|
|
69
99
|
"""
|
|
70
100
|
if not isinstance(frame, (pl.DataFrame, pl.LazyFrame)):
|
|
71
101
|
raise TypeError("frame must be a Polars DataFrame or LazyFrame.")
|
|
72
102
|
|
|
103
|
+
within_cols = list(within_cols or [])
|
|
104
|
+
sibling_priority_cols = list(sibling_priority_cols or [])
|
|
105
|
+
|
|
73
106
|
original_offer = "__original_offer_for_imputation__"
|
|
74
107
|
|
|
75
108
|
def as_rule_expr(rule: Union[pl.Expr, Callable[[Frame], pl.Expr]]) -> pl.Expr:
|
|
@@ -78,16 +111,21 @@ def impute_offers(
|
|
|
78
111
|
raise TypeError("Imputation rules must be Polars expressions.")
|
|
79
112
|
return expr.fill_null(False)
|
|
80
113
|
|
|
81
|
-
def any_sibling_priority(cols:
|
|
82
|
-
if not cols:
|
|
83
|
-
return pl.lit(False)
|
|
84
|
-
|
|
114
|
+
def any_sibling_priority(cols: Sequence[str]) -> pl.Expr:
|
|
85
115
|
priority_expr = pl.lit(False)
|
|
86
116
|
for col in cols:
|
|
87
117
|
priority_expr = priority_expr | (pl.col(col).fill_null(0) == 1)
|
|
88
118
|
return priority_expr
|
|
89
119
|
|
|
90
|
-
|
|
120
|
+
def maybe_over(expr: pl.Expr) -> pl.Expr:
|
|
121
|
+
if within_cols:
|
|
122
|
+
return expr.over(within_cols)
|
|
123
|
+
return expr
|
|
124
|
+
|
|
125
|
+
work = frame.with_columns(
|
|
126
|
+
pl.col(offer_col).fill_null(0).cast(pl.Int8, strict=False).alias(original_offer)
|
|
127
|
+
)
|
|
128
|
+
|
|
91
129
|
originally_no_offer = pl.col(original_offer) == 0
|
|
92
130
|
|
|
93
131
|
lottery_rule = None
|
|
@@ -99,7 +137,7 @@ def impute_offers(
|
|
|
99
137
|
& ~any_sibling_priority(sibling_priority_cols)
|
|
100
138
|
)
|
|
101
139
|
|
|
102
|
-
lottery_cutoff = (
|
|
140
|
+
lottery_cutoff = maybe_over(
|
|
103
141
|
pl.col(lottery_number_col)
|
|
104
142
|
.filter(observed_regular_offer)
|
|
105
143
|
.max()
|
|
@@ -125,7 +163,7 @@ def impute_offers(
|
|
|
125
163
|
else:
|
|
126
164
|
waitlist_cutoff_source = pl.col(original_offer) == 1
|
|
127
165
|
|
|
128
|
-
waitlist_cutoff = (
|
|
166
|
+
waitlist_cutoff = maybe_over(
|
|
129
167
|
pl.col(waitlist_number_col)
|
|
130
168
|
.filter(waitlist_cutoff_source)
|
|
131
169
|
.max()
|
|
@@ -176,8 +214,6 @@ def impute_offers(
|
|
|
176
214
|
)
|
|
177
215
|
|
|
178
216
|
|
|
179
|
-
|
|
180
|
-
|
|
181
217
|
# mappings.py
|
|
182
218
|
|
|
183
219
|
import polars as pl
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|