ltc-code 0.1.96__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.96 → ltc_code-0.1.98}/PKG-INFO +1 -1
- {ltc_code-0.1.96 → ltc_code-0.1.98}/pyproject.toml +1 -1
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/june13.py +58 -70
- {ltc_code-0.1.96 → ltc_code-0.1.98}/README.md +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/__init__.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/aspire.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/check_cmo_apps.do +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/christel_house.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/green_dot.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/helpers.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/june2.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/june5.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/june7.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/kipp_nj.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/kipp_tx.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/main.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/mappings.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/may27.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/polars_dates.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/rocketship.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/schema_mapping.py +0 -0
- {ltc_code-0.1.96 → ltc_code-0.1.98}/src/ltc_code/yes_prep.py +0 -0
|
@@ -2,6 +2,18 @@ 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
|
+
|
|
12
|
+
|
|
13
|
+
from typing import Callable, Optional, Sequence, Union
|
|
14
|
+
|
|
15
|
+
import polars as pl
|
|
16
|
+
|
|
5
17
|
|
|
6
18
|
def impute_offers(
|
|
7
19
|
frame: Union[pl.DataFrame, pl.LazyFrame],
|
|
@@ -9,131 +21,110 @@ def impute_offers(
|
|
|
9
21
|
lottery_number_col: Optional[str] = None,
|
|
10
22
|
waitlist_number_col: Optional[str] = None,
|
|
11
23
|
enrollment_col: Optional[str] = None,
|
|
12
|
-
lottery_imputation: Optional[Union[pl.Expr, Callable[[
|
|
13
|
-
waitlist_imputation: Optional[Union[pl.Expr, Callable[[
|
|
14
|
-
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,
|
|
15
27
|
sibling_priority_cols: Optional[Sequence[str]] = None,
|
|
28
|
+
within_cols: Optional[Sequence[str]] = None,
|
|
16
29
|
) -> Union[pl.DataFrame, pl.LazyFrame]:
|
|
17
30
|
"""
|
|
18
31
|
Impute offer indicators in a Polars DataFrame or LazyFrame.
|
|
19
32
|
|
|
20
|
-
The function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
for the same row if multiple rules independently imply an offer.
|
|
30
|
-
|
|
31
|
-
Default rules:
|
|
32
|
-
- Lottery: find the highest lottery number among observed offers, excluding
|
|
33
|
-
sibling-priority offers when ``sibling_priority_cols`` is supplied. Impute
|
|
34
|
-
offers for all originally non-offered rows with lottery numbers at or
|
|
35
|
-
below that cutoff.
|
|
36
|
-
- Enrollment: impute offers for originally non-offered enrolled rows.
|
|
37
|
-
- Waitlist:
|
|
38
|
-
* If enrollment information is supplied, first infer offers from
|
|
39
|
-
enrollment, then use the highest waitlist number among those
|
|
40
|
-
enrollment-implied offers as the waitlist cutoff.
|
|
41
|
-
* If enrollment information is not supplied, use the highest waitlist
|
|
42
|
-
number among observed offers as the waitlist cutoff.
|
|
43
|
-
Then impute offers for all originally non-offered rows with waitlist
|
|
44
|
-
numbers at or below the cutoff.
|
|
45
|
-
|
|
46
|
-
Custom rules may be supplied as Polars expressions or as callables that
|
|
47
|
-
accept the frame and return a Polars expression.
|
|
48
|
-
|
|
49
|
-
Example
|
|
50
|
-
-------
|
|
51
|
-
>>> df = pl.DataFrame({
|
|
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(
|
|
60
|
-
... df,
|
|
61
|
-
... offer_col="offer",
|
|
62
|
-
... lottery_number_col="lottery_num",
|
|
63
|
-
... waitlist_number_col="waitlist_num",
|
|
64
|
-
... enrollment_col="enrolled",
|
|
65
|
-
... sibling_priority_cols=["sib_1", "sib_2"],
|
|
66
|
-
... )
|
|
67
|
-
shape: (4, 9)
|
|
68
|
-
...
|
|
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.
|
|
69
42
|
"""
|
|
70
43
|
if not isinstance(frame, (pl.DataFrame, pl.LazyFrame)):
|
|
71
44
|
raise TypeError("frame must be a Polars DataFrame or LazyFrame.")
|
|
72
45
|
|
|
46
|
+
within_cols = list(within_cols or [])
|
|
47
|
+
sibling_priority_cols = list(sibling_priority_cols or [])
|
|
48
|
+
|
|
73
49
|
original_offer = "__original_offer_for_imputation__"
|
|
74
50
|
|
|
75
|
-
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:
|
|
76
52
|
expr = rule(frame) if callable(rule) else rule
|
|
77
53
|
if not isinstance(expr, pl.Expr):
|
|
78
54
|
raise TypeError("Imputation rules must be Polars expressions.")
|
|
79
55
|
return expr.fill_null(False)
|
|
80
56
|
|
|
81
|
-
def
|
|
82
|
-
|
|
83
|
-
|
|
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)
|
|
84
62
|
|
|
63
|
+
def any_sibling_priority(cols: Sequence[str]) -> pl.Expr:
|
|
85
64
|
priority_expr = pl.lit(False)
|
|
86
65
|
for col in cols:
|
|
87
|
-
priority_expr = priority_expr | (
|
|
66
|
+
priority_expr = priority_expr | (binary_col(col) == 1)
|
|
88
67
|
return priority_expr
|
|
89
68
|
|
|
90
|
-
|
|
69
|
+
def maybe_over(expr: pl.Expr) -> pl.Expr:
|
|
70
|
+
if within_cols:
|
|
71
|
+
return expr.over(within_cols)
|
|
72
|
+
return expr
|
|
73
|
+
|
|
74
|
+
work = frame.with_columns(
|
|
75
|
+
binary_col(offer_col).cast(pl.Int8, strict=False).alias(original_offer)
|
|
76
|
+
)
|
|
77
|
+
|
|
91
78
|
originally_no_offer = pl.col(original_offer) == 0
|
|
92
79
|
|
|
93
80
|
lottery_rule = None
|
|
94
81
|
if lottery_imputation is not None:
|
|
95
82
|
lottery_rule = as_rule_expr(lottery_imputation)
|
|
96
83
|
elif lottery_number_col is not None:
|
|
84
|
+
lottery_number = number_col(lottery_number_col)
|
|
85
|
+
|
|
97
86
|
observed_regular_offer = (
|
|
98
87
|
(pl.col(original_offer) == 1)
|
|
99
88
|
& ~any_sibling_priority(sibling_priority_cols)
|
|
100
89
|
)
|
|
101
90
|
|
|
102
|
-
lottery_cutoff = (
|
|
103
|
-
|
|
91
|
+
lottery_cutoff = maybe_over(
|
|
92
|
+
lottery_number
|
|
104
93
|
.filter(observed_regular_offer)
|
|
105
94
|
.max()
|
|
106
95
|
)
|
|
107
96
|
|
|
108
97
|
lottery_rule = (
|
|
109
|
-
|
|
110
|
-
& (
|
|
98
|
+
lottery_number.is_not_null()
|
|
99
|
+
& (lottery_number <= lottery_cutoff)
|
|
111
100
|
).fill_null(False)
|
|
112
101
|
|
|
113
102
|
enrollment_rule = None
|
|
114
103
|
if enrollment_imputation is not None:
|
|
115
104
|
enrollment_rule = as_rule_expr(enrollment_imputation)
|
|
116
105
|
elif enrollment_col is not None:
|
|
117
|
-
enrollment_rule = (
|
|
106
|
+
enrollment_rule = (binary_col(enrollment_col) == 1).fill_null(False)
|
|
118
107
|
|
|
119
108
|
waitlist_rule = None
|
|
120
109
|
if waitlist_imputation is not None:
|
|
121
110
|
waitlist_rule = as_rule_expr(waitlist_imputation)
|
|
122
111
|
elif waitlist_number_col is not None:
|
|
112
|
+
waitlist_number = number_col(waitlist_number_col)
|
|
113
|
+
|
|
123
114
|
if enrollment_rule is not None:
|
|
124
115
|
waitlist_cutoff_source = originally_no_offer & enrollment_rule
|
|
125
116
|
else:
|
|
126
117
|
waitlist_cutoff_source = pl.col(original_offer) == 1
|
|
127
118
|
|
|
128
|
-
waitlist_cutoff = (
|
|
129
|
-
|
|
119
|
+
waitlist_cutoff = maybe_over(
|
|
120
|
+
waitlist_number
|
|
130
121
|
.filter(waitlist_cutoff_source)
|
|
131
122
|
.max()
|
|
132
123
|
)
|
|
133
124
|
|
|
134
125
|
waitlist_rule = (
|
|
135
|
-
|
|
136
|
-
& (
|
|
126
|
+
waitlist_number.is_not_null()
|
|
127
|
+
& (waitlist_number <= waitlist_cutoff)
|
|
137
128
|
).fill_null(False)
|
|
138
129
|
|
|
139
130
|
false_expr = pl.lit(False)
|
|
@@ -175,9 +166,6 @@ def impute_offers(
|
|
|
175
166
|
.drop(original_offer)
|
|
176
167
|
)
|
|
177
168
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
169
|
# mappings.py
|
|
182
170
|
|
|
183
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
|