ltc-code 0.2.27__tar.gz → 0.2.29__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.2.27 → ltc_code-0.2.29}/PKG-INFO +1 -1
- {ltc_code-0.2.27 → ltc_code-0.2.29}/pyproject.toml +5 -1
- ltc_code-0.2.29/src/ltc_code/nsc/NEW_CROSSWALK.md +24 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/nsc/build_nsc_outcomes.py +68 -15
- ltc_code-0.2.29/src/ltc_code/nsc/build_nsc_outcomes_new.py +2162 -0
- ltc_code-0.2.29/src/ltc_code/nsc/naics.csv +25 -0
- ltc_code-0.2.29/src/ltc_code/nsc/naics_raw.xlsx +0 -0
- ltc_code-0.2.29/src/ltc_code/nsc/raw/CREDENTIAL_LEVEL_LOOKUP_TABLE.xlsx +0 -0
- ltc_code-0.2.29/src/ltc_code/nsc/raw/IPEDS_IC_2013.csv +7647 -0
- ltc_code-0.2.29/src/ltc_code/nsc/raw/IPEDS_IC_manual.xlsx +0 -0
- ltc_code-0.2.29/src/ltc_code/nsc/raw/NSC_SCHOOL_CODE_TO_IPEDS_UNIT_ID_XWALK_APR-2023.xlsx +0 -0
- ltc_code-0.2.29/src/ltc_code/nsc/raw/chetty/mrc_table11.dta +0 -0
- ltc_code-0.2.29/src/ltc_code/nsc/raw/chetty/mrc_table2.dta +0 -0
- ltc_code-0.2.29/src/ltc_code/nsc/raw/college_crosswalk.xls +0 -0
- ltc_code-0.2.29/src/ltc_code/nsc/raw/directory.dta +0 -0
- ltc_code-0.2.29/src/ltc_code/plot_bars.py +84 -0
- ltc_code-0.2.27/pyproject.toml.orig +0 -19
- ltc_code-0.2.27/src/ltc_code/nsc/input/.gitkeep +0 -0
- ltc_code-0.2.27/src/ltc_code/nsc/output/.gitkeep +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/README.md +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/aspire.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/check_cmo_apps.do +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/christel_house.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/democracy_prep.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/green_dot.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/helpers.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/ilt.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/kipp_nj.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/main.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/mappings.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/rocketship.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260614_new_build_scripts_update/yes_prep.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260630_census_disclosure/aspire.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260630_census_disclosure/christel_house.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260630_census_disclosure/democracy_prep.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260630_census_disclosure/green_dot.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260630_census_disclosure/ilt.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260630_census_disclosure/kipp.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260630_census_disclosure/kipp_nj.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260630_census_disclosure/rocketship.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260630_census_disclosure/yes_prep.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260706_ceprscripts/BALANCE.do +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260706_ceprscripts/FS.do +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260706_ceprscripts/ITT.do +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260706_ceprscripts/TOT.do +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260706_ceprscripts/apps_helpers.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260706_ceprscripts/harmony.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260706_ceprscripts/main.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260712_uncommon_scripts/main.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260712_uncommon_scripts/mappings.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/20260712_uncommon_scripts/uncommon.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/__init__.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/aspire.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/check_cmo_apps.do +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/christel_house.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/green_dot.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/helpers.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/june13.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/june2.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/june30.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/june5.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/june7.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/kipp_nj.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/kipp_tx.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/main.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/make_summary_stats_table.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/mappings.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/may27.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/nsc/__init__.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/nsc/dhs_stem/dhs_stem_cip_additions_2024.csv +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/nsc/dhs_stem/extract_dhs_stem_cips.R +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/nsc/dhs_stem/stemList2024.pdf +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/nsc/naics.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/nsc/raw/ipeds_data.dta +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/nsc/run_nsc_outcomes.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/polars_dates.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/rocketship.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/schema_mapping.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/school_name_xwalk/__init__.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/school_name_xwalk/all_schools_with_ccd.csv +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/school_name_xwalk/merge_school_ccd.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/signal_var_calcs.py +0 -0
- {ltc_code-0.2.27 → ltc_code-0.2.29}/src/ltc_code/yes_prep.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ltc-code"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.29"
|
|
4
4
|
description = "Add your description here"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.9"
|
|
@@ -17,3 +17,7 @@ ltc-summary-stats = "ltc_code.make_summary_stats_table:main"
|
|
|
17
17
|
[build-system]
|
|
18
18
|
requires = ["uv_build>=0.11.16,<0.12.0"]
|
|
19
19
|
build-backend = "uv_build"
|
|
20
|
+
|
|
21
|
+
[tool.uv.build-backend]
|
|
22
|
+
source-exclude = ["**/.DS_Store", "**/__pycache__/**", "**/*.pyc", "src/ltc_code/nsc/input/**", "src/ltc_code/nsc/output/**"]
|
|
23
|
+
wheel-exclude = ["**/.DS_Store", "**/__pycache__/**", "**/*.pyc", "ltc_code/nsc/input/**", "ltc_code/nsc/output/**"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# New NSC crosswalk build
|
|
2
|
+
|
|
3
|
+
Run the new variant explicitly with `python -m ltc_code.nsc.build_nsc_outcomes_new` after providing the student input files. The original build remains available. The new variant writes to `nsc/output/new_crosswalk/` to keep its outputs separate.
|
|
4
|
+
|
|
5
|
+
The official April 2023 NSC crosswalk is primary. Append mapped legacy codes only when their full lookup key is absent from the official file. Do not fill the 108 present-but-blank official keys using Sarah's mappings. Existing 18 sole-rate candidate choices and 24 Calhoun branch assignments are explicit and documented in the code. Preserve full branch codes and deterministic legacy selection.
|
|
6
|
+
|
|
7
|
+
Institution type uses IPEDS 2013, then the latest nonmissing directory classification, then three inline exceptions formerly loaded from the manual spreadsheet. Less-than-two-year labels are parsed before broader two-year labels. Treat Missing/not reported as null before choosing the latest directory record. The existing two-year-or-less outcome grouping is retained. The 5–8 tier bucket lookup counts Nevada State once despite its tier 5/7 aliases.
|
|
8
|
+
|
|
9
|
+
All student outcome formulas, eligibility windows, completion-rate imputation, and the existing within-bucket coarse-rate exercise remain unchanged. The change affects their institutional inputs. No annual enrollment-year classification is introduced.
|
|
10
|
+
|
|
11
|
+
Expected counts with the audited files: 24,166 keys; 21,315 with UNITID; 21,204 matching a UNITID in the 2013/directory files (99.479%); 7,867 matched institutions with no missing type. Distinct institution types: 3,329 four-year, 2,440 two-year, 2,098 less-than-two-year. These are reference-table counts, not secure-sample match rates or completeness of completion rates.
|
|
12
|
+
|
|
13
|
+
Required files in `nsc/raw/`:
|
|
14
|
+
- NSC_SCHOOL_CODE_TO_IPEDS_UNIT_ID_XWALK_APR-2023.xlsx (official workbook, NSC_to_IPEDS_UNIT_ID sheet)
|
|
15
|
+
- college_crosswalk.xls (legacy fallback)
|
|
16
|
+
- IPEDS_IC_2013.csv
|
|
17
|
+
- directory.dta
|
|
18
|
+
- CREDENTIAL_LEVEL_LOOKUP_TABLE.xlsx
|
|
19
|
+
- ipeds_data.dta
|
|
20
|
+
- chetty/mrc_table2.dta and chetty/mrc_table11.dta
|
|
21
|
+
|
|
22
|
+
The old IPEDS_IC_manual.xlsx is not needed by this variant. Student inputs remain input/apps.csv, input/nsc_records_old.dta, and input/nsc_records_new.csv. Do not supply synthetic records for actual analysis. Institutional support files are bundled in the locally built wheel and source distribution but are Git-ignored. GitHub Actions publishes these verified distributions from release assets; it does not rebuild from a checkout that lacks the data. Student inputs are never bundled.
|
|
23
|
+
|
|
24
|
+
Institution-only audit CSVs are written alongside the outcomes, including mapping choices, appended candidates, missing UNITIDs, and missing classifications. The 99.48% matched subset is an audit denominator, not a filter that drops student records from the build.
|
|
@@ -1198,9 +1198,10 @@ for year in range(1, N_YEARS_OUT + 1):
|
|
|
1198
1198
|
[
|
|
1199
1199
|
(
|
|
1200
1200
|
pl.col("_overlaps")
|
|
1201
|
-
*
|
|
1202
|
-
|
|
1203
|
-
|
|
1201
|
+
* (
|
|
1202
|
+
pl.lit(1) if college_type == "any"
|
|
1203
|
+
else pl.col(f"college_{college_type}").fill_null(0).cast(pl.Int8)
|
|
1204
|
+
)
|
|
1204
1205
|
)
|
|
1205
1206
|
.max()
|
|
1206
1207
|
.alias(f"att_{college_type}_{label}")
|
|
@@ -1258,9 +1259,10 @@ for age in AGE_ATTENDANCE_RANGE:
|
|
|
1258
1259
|
[
|
|
1259
1260
|
(
|
|
1260
1261
|
pl.col("_overlaps")
|
|
1261
|
-
*
|
|
1262
|
-
|
|
1263
|
-
|
|
1262
|
+
* (
|
|
1263
|
+
pl.lit(1) if college_type == "any"
|
|
1264
|
+
else pl.col(f"college_{college_type}").fill_null(0).cast(pl.Int8)
|
|
1265
|
+
)
|
|
1264
1266
|
)
|
|
1265
1267
|
.max()
|
|
1266
1268
|
.alias(f"att_{college_type}_{age}")
|
|
@@ -1878,6 +1880,60 @@ nsc_outcomes = nsc_outcomes.with_columns(
|
|
|
1878
1880
|
.alias("adj_cmp_rate_2yr"),
|
|
1879
1881
|
)
|
|
1880
1882
|
|
|
1883
|
+
# Separate the fully coarse prediction by first-institution sector.
|
|
1884
|
+
nsc_outcomes = nsc_outcomes.with_columns(
|
|
1885
|
+
pl.when(
|
|
1886
|
+
pl.col("adj_cmp_rate_coarse").is_not_null()
|
|
1887
|
+
& pl.col("college_years_firstinst").is_in([1, 2])
|
|
1888
|
+
)
|
|
1889
|
+
.then(0.0)
|
|
1890
|
+
.otherwise(pl.col("adj_cmp_rate_coarse"))
|
|
1891
|
+
.alias("adj_cmp_rate_coarse_4yr"),
|
|
1892
|
+
pl.when(
|
|
1893
|
+
pl.col("adj_cmp_rate_coarse").is_not_null()
|
|
1894
|
+
& (pl.col("college_years_firstinst") == 4)
|
|
1895
|
+
)
|
|
1896
|
+
.then(0.0)
|
|
1897
|
+
.otherwise(pl.col("adj_cmp_rate_coarse"))
|
|
1898
|
+
.alias("adj_cmp_rate_coarse_2yr"),
|
|
1899
|
+
)
|
|
1900
|
+
|
|
1901
|
+
# Only tiers 1-8 enter these four-year bucket averages. Other-tier branch
|
|
1902
|
+
# mappings can share a UNITID and must not duplicate the institution's cohort.
|
|
1903
|
+
ipeds_tiers = (
|
|
1904
|
+
college_ref.select("unitid", "tier")
|
|
1905
|
+
.drop_nulls()
|
|
1906
|
+
.filter(pl.col("tier").is_in(range(1, 9)))
|
|
1907
|
+
.unique()
|
|
1908
|
+
)
|
|
1909
|
+
ipeds_tier_completion = ipeds_completion_with_sector.join(
|
|
1910
|
+
ipeds_tiers, on="unitid", how="left", validate="1:1"
|
|
1911
|
+
).filter(pl.col("college_sector") == "4yr")
|
|
1912
|
+
|
|
1913
|
+
# Coarsen one bucket at a time, always starting from the detailed prediction.
|
|
1914
|
+
tier_buckets = {"t12": [1, 2], "t34": [3, 4], "t58": [5, 6, 7, 8]}
|
|
1915
|
+
for label, tiers in tier_buckets.items():
|
|
1916
|
+
bucket_rate = (
|
|
1917
|
+
ipeds_tier_completion.filter(pl.col("tier").is_in(tiers))
|
|
1918
|
+
.select(
|
|
1919
|
+
pl.col("completers_150pct_ip").sum()
|
|
1920
|
+
/ pl.col("cohort_adj_150pct_ip").sum()
|
|
1921
|
+
)
|
|
1922
|
+
.item()
|
|
1923
|
+
)
|
|
1924
|
+
nsc_outcomes = nsc_outcomes.with_columns(
|
|
1925
|
+
pl.when(
|
|
1926
|
+
(pl.col("college_years_firstinst") == 4)
|
|
1927
|
+
& pl.col("tier_firstinst").is_in(tiers)
|
|
1928
|
+
& (pl.col("att_any_byY4") == 1)
|
|
1929
|
+
& pl.col("adj_cmp_rate_4yr").is_not_null()
|
|
1930
|
+
)
|
|
1931
|
+
.then(bucket_rate)
|
|
1932
|
+
.otherwise(pl.col("adj_cmp_rate_4yr"))
|
|
1933
|
+
.alias(f"adj_cmp_rate_4yr_coarse_{label}")
|
|
1934
|
+
)
|
|
1935
|
+
print(f"Four-year IPEDS-cohort-weighted completion rate, {label}: {bucket_rate}")
|
|
1936
|
+
|
|
1881
1937
|
# Match the available 1098-T calendar years, including the missing 2015 year.
|
|
1882
1938
|
tax_years = list(range(2011, 2015)) + list(range(2016, 2023))
|
|
1883
1939
|
nsc_outcomes = nsc_outcomes.with_columns(
|
|
@@ -1888,6 +1944,7 @@ nsc_outcomes = nsc_outcomes.with_columns(
|
|
|
1888
1944
|
.alias(f"att_any_1098_{age}")
|
|
1889
1945
|
for age in AGE_ATTENDANCE_RANGE
|
|
1890
1946
|
]
|
|
1947
|
+
|
|
1891
1948
|
)
|
|
1892
1949
|
|
|
1893
1950
|
|
|
@@ -1966,6 +2023,9 @@ keep_columns = [
|
|
|
1966
2023
|
"adj_cmp_rate",
|
|
1967
2024
|
"adj_cmp_rate_2yr",
|
|
1968
2025
|
"adj_cmp_rate_4yr",
|
|
2026
|
+
"adj_cmp_rate_coarse_2yr",
|
|
2027
|
+
"adj_cmp_rate_coarse_4yr",
|
|
2028
|
+
*[f"adj_cmp_rate_4yr_coarse_{label}" for label in tier_buckets],
|
|
1969
2029
|
"adj_cmp_rate_coarse",
|
|
1970
2030
|
"adj_cmp_rate_coarse_sample",
|
|
1971
2031
|
"adj_cmp_rate_coarsen_4yr",
|
|
@@ -2046,15 +2106,8 @@ coarse_audit = observable_y4.select(
|
|
|
2046
2106
|
|
|
2047
2107
|
if coarse_audit.item(0, "k_mean_coarse_missing") > 0:
|
|
2048
2108
|
raise ValueError("k_mean_coarse is unexpectedly missing for observable students.")
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
"adj_cmp_rate_coarse is unexpectedly missing for observable students."
|
|
2052
|
-
)
|
|
2053
|
-
if coarse_audit.item(0, "adj_cmp_rate_coarse_sample_missing") > 0:
|
|
2054
|
-
raise ValueError(
|
|
2055
|
-
"adj_cmp_rate_coarse_sample is unexpectedly missing for observable students."
|
|
2056
|
-
)
|
|
2057
|
-
|
|
2109
|
+
# Attendees without a classified first college can have missing coarse rates.
|
|
2110
|
+
# Report those counts below rather than treating them as a build failure.
|
|
2058
2111
|
print("Coarse outcome audit:")
|
|
2059
2112
|
print(coarse_audit)
|
|
2060
2113
|
|