ltc-code 0.1.97__tar.gz → 0.1.98__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.97 → ltc_code-0.1.98}/PKG-INFO +1 -1
- {ltc_code-0.1.97 → ltc_code-0.1.98}/pyproject.toml +1 -1
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/june13.py +37 -85
- {ltc_code-0.1.97 → ltc_code-0.1.98}/README.md +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/__init__.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/aspire.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/check_cmo_apps.do +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/christel_house.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/green_dot.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/helpers.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/june2.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/june5.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/june7.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/kipp_nj.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/kipp_tx.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/main.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/mappings.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/may27.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/polars_dates.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/rocketship.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/schema_mapping.py +0 -0
- {ltc_code-0.1.97 → ltc_code-0.1.98}/src/ltc_code/yes_prep.py +0 -0
|
@@ -10,92 +10,35 @@ Frame =
|
|
|
10
10
|
Rule = Union[pl.Expr, Callable[[Frame], pl.Expr]]
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
from typing import Callable, Optional, Sequence, Union
|
|
14
|
+
|
|
15
|
+
import polars as pl
|
|
16
|
+
|
|
17
|
+
|
|
13
18
|
def impute_offers(
|
|
14
19
|
frame: Union[pl.DataFrame, pl.LazyFrame],
|
|
15
20
|
offer_col: str,
|
|
16
21
|
lottery_number_col: Optional[str] = None,
|
|
17
22
|
waitlist_number_col: Optional[str] = None,
|
|
18
23
|
enrollment_col: Optional[str] = None,
|
|
19
|
-
lottery_imputation: Optional[Union[pl.Expr, Callable[[
|
|
20
|
-
waitlist_imputation: Optional[Union[pl.Expr, Callable[[
|
|
21
|
-
enrollment_imputation: Optional[Union[pl.Expr, Callable[[
|
|
24
|
+
lottery_imputation: Optional[Union[pl.Expr, Callable[[Union[pl.DataFrame, pl.LazyFrame]], pl.Expr]]] = None,
|
|
25
|
+
waitlist_imputation: Optional[Union[pl.Expr, Callable[[Union[pl.DataFrame, pl.LazyFrame]], pl.Expr]]] = None,
|
|
26
|
+
enrollment_imputation: Optional[Union[pl.Expr, Callable[[Union[pl.DataFrame, pl.LazyFrame]], pl.Expr]]] = None,
|
|
22
27
|
sibling_priority_cols: Optional[Sequence[str]] = None,
|
|
23
28
|
within_cols: Optional[Sequence[str]] = None,
|
|
24
29
|
) -> Union[pl.DataFrame, pl.LazyFrame]:
|
|
25
30
|
"""
|
|
26
31
|
Impute offer indicators in a Polars DataFrame or LazyFrame.
|
|
27
32
|
|
|
28
|
-
The function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
for the same row if multiple rules independently imply an offer.
|
|
38
|
-
|
|
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.
|
|
87
|
-
|
|
88
|
-
Example
|
|
89
|
-
-------
|
|
90
|
-
>>> result = impute_offers(
|
|
91
|
-
... df,
|
|
92
|
-
... offer_col="offer",
|
|
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"],
|
|
98
|
-
... )
|
|
33
|
+
The function safely casts provided 0/1 and numeric order columns before
|
|
34
|
+
comparing them, so columns stored as strings like ``"0"``, ``"1"``, or
|
|
35
|
+
``"12"`` can still be used.
|
|
36
|
+
|
|
37
|
+
Binary columns are interpreted as 1 only when they cast cleanly to numeric
|
|
38
|
+
value 1. Nulls and non-numeric strings are treated as 0.
|
|
39
|
+
|
|
40
|
+
Lottery and waitlist number columns are cast to Float64 for cutoff
|
|
41
|
+
comparisons. Nulls and non-numeric strings are ignored.
|
|
99
42
|
"""
|
|
100
43
|
if not isinstance(frame, (pl.DataFrame, pl.LazyFrame)):
|
|
101
44
|
raise TypeError("frame must be a Polars DataFrame or LazyFrame.")
|
|
@@ -105,16 +48,22 @@ def impute_offers(
|
|
|
105
48
|
|
|
106
49
|
original_offer = "__original_offer_for_imputation__"
|
|
107
50
|
|
|
108
|
-
def as_rule_expr(rule: Union[pl.Expr, Callable[[
|
|
51
|
+
def as_rule_expr(rule: Union[pl.Expr, Callable[[Union[pl.DataFrame, pl.LazyFrame]], pl.Expr]]) -> pl.Expr:
|
|
109
52
|
expr = rule(frame) if callable(rule) else rule
|
|
110
53
|
if not isinstance(expr, pl.Expr):
|
|
111
54
|
raise TypeError("Imputation rules must be Polars expressions.")
|
|
112
55
|
return expr.fill_null(False)
|
|
113
56
|
|
|
57
|
+
def binary_col(col: str) -> pl.Expr:
|
|
58
|
+
return pl.col(col).cast(pl.Float64, strict=False).fill_null(0)
|
|
59
|
+
|
|
60
|
+
def number_col(col: str) -> pl.Expr:
|
|
61
|
+
return pl.col(col).cast(pl.Float64, strict=False)
|
|
62
|
+
|
|
114
63
|
def any_sibling_priority(cols: Sequence[str]) -> pl.Expr:
|
|
115
64
|
priority_expr = pl.lit(False)
|
|
116
65
|
for col in cols:
|
|
117
|
-
priority_expr = priority_expr | (
|
|
66
|
+
priority_expr = priority_expr | (binary_col(col) == 1)
|
|
118
67
|
return priority_expr
|
|
119
68
|
|
|
120
69
|
def maybe_over(expr: pl.Expr) -> pl.Expr:
|
|
@@ -123,7 +72,7 @@ def impute_offers(
|
|
|
123
72
|
return expr
|
|
124
73
|
|
|
125
74
|
work = frame.with_columns(
|
|
126
|
-
|
|
75
|
+
binary_col(offer_col).cast(pl.Int8, strict=False).alias(original_offer)
|
|
127
76
|
)
|
|
128
77
|
|
|
129
78
|
originally_no_offer = pl.col(original_offer) == 0
|
|
@@ -132,46 +81,50 @@ def impute_offers(
|
|
|
132
81
|
if lottery_imputation is not None:
|
|
133
82
|
lottery_rule = as_rule_expr(lottery_imputation)
|
|
134
83
|
elif lottery_number_col is not None:
|
|
84
|
+
lottery_number = number_col(lottery_number_col)
|
|
85
|
+
|
|
135
86
|
observed_regular_offer = (
|
|
136
87
|
(pl.col(original_offer) == 1)
|
|
137
88
|
& ~any_sibling_priority(sibling_priority_cols)
|
|
138
89
|
)
|
|
139
90
|
|
|
140
91
|
lottery_cutoff = maybe_over(
|
|
141
|
-
|
|
92
|
+
lottery_number
|
|
142
93
|
.filter(observed_regular_offer)
|
|
143
94
|
.max()
|
|
144
95
|
)
|
|
145
96
|
|
|
146
97
|
lottery_rule = (
|
|
147
|
-
|
|
148
|
-
& (
|
|
98
|
+
lottery_number.is_not_null()
|
|
99
|
+
& (lottery_number <= lottery_cutoff)
|
|
149
100
|
).fill_null(False)
|
|
150
101
|
|
|
151
102
|
enrollment_rule = None
|
|
152
103
|
if enrollment_imputation is not None:
|
|
153
104
|
enrollment_rule = as_rule_expr(enrollment_imputation)
|
|
154
105
|
elif enrollment_col is not None:
|
|
155
|
-
enrollment_rule = (
|
|
106
|
+
enrollment_rule = (binary_col(enrollment_col) == 1).fill_null(False)
|
|
156
107
|
|
|
157
108
|
waitlist_rule = None
|
|
158
109
|
if waitlist_imputation is not None:
|
|
159
110
|
waitlist_rule = as_rule_expr(waitlist_imputation)
|
|
160
111
|
elif waitlist_number_col is not None:
|
|
112
|
+
waitlist_number = number_col(waitlist_number_col)
|
|
113
|
+
|
|
161
114
|
if enrollment_rule is not None:
|
|
162
115
|
waitlist_cutoff_source = originally_no_offer & enrollment_rule
|
|
163
116
|
else:
|
|
164
117
|
waitlist_cutoff_source = pl.col(original_offer) == 1
|
|
165
118
|
|
|
166
119
|
waitlist_cutoff = maybe_over(
|
|
167
|
-
|
|
120
|
+
waitlist_number
|
|
168
121
|
.filter(waitlist_cutoff_source)
|
|
169
122
|
.max()
|
|
170
123
|
)
|
|
171
124
|
|
|
172
125
|
waitlist_rule = (
|
|
173
|
-
|
|
174
|
-
& (
|
|
126
|
+
waitlist_number.is_not_null()
|
|
127
|
+
& (waitlist_number <= waitlist_cutoff)
|
|
175
128
|
).fill_null(False)
|
|
176
129
|
|
|
177
130
|
false_expr = pl.lit(False)
|
|
@@ -213,7 +166,6 @@ def impute_offers(
|
|
|
213
166
|
.drop(original_offer)
|
|
214
167
|
)
|
|
215
168
|
|
|
216
|
-
|
|
217
169
|
# mappings.py
|
|
218
170
|
|
|
219
171
|
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
|