latex
@@ -44,7 +44,8 @@ def truncation_correction(mu, sigma, C, p_thresh):
|
||||
if p_trunc < p_thresh:
|
||||
return mu, p_trunc, False
|
||||
else:
|
||||
mu_tilde = mu * (1 + 0.4 * p_trunc)
|
||||
# 与主流程 `02_demand_correction.py` 保持一致:线性修正系数 0.1
|
||||
mu_tilde = mu * (1 + 0.1 * p_trunc)
|
||||
return mu_tilde, p_trunc, True
|
||||
|
||||
|
||||
|
||||
121
task1/export_paper_tables.py
Normal file
@@ -0,0 +1,121 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
import pandas as pd
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
OUT_DIR = ROOT / "paper_tables"
|
||||
|
||||
|
||||
def _to_int_series(s: pd.Series) -> pd.Series:
|
||||
return s.map(lambda x: int(round(float(x))) if pd.notna(x) else x)
|
||||
|
||||
|
||||
def _to_float_series(s: pd.Series, ndigits: int) -> pd.Series:
|
||||
return s.map(lambda x: round(float(x), ndigits) if pd.notna(x) else x)
|
||||
|
||||
|
||||
def _format_table1_metrics_summary(df: pd.DataFrame) -> pd.DataFrame:
|
||||
out = df.copy()
|
||||
out["E1_total_service"] = _to_int_series(out["E1_total_service"])
|
||||
out["E2_quality_weighted"] = _to_int_series(out["E2_quality_weighted"])
|
||||
out["F1_gini"] = _to_float_series(out["F1_gini"], 4)
|
||||
out["F2_min_satisfaction"] = _to_float_series(out["F2_min_satisfaction"], 2)
|
||||
out["F3_cv_satisfaction"] = _to_float_series(out["F3_cv_satisfaction"], 4)
|
||||
out["E1_total_service_pct"] = _to_float_series(out["E1_total_service_pct"], 2)
|
||||
out["E2_quality_weighted_pct"] = _to_float_series(out["E2_quality_weighted_pct"], 2)
|
||||
return out
|
||||
|
||||
|
||||
def _format_table2_corrected_sites(df: pd.DataFrame) -> pd.DataFrame:
|
||||
out = df.copy()
|
||||
out["site_id"] = _to_int_series(out["site_id"])
|
||||
out["mu"] = _to_float_series(out["mu"], 1)
|
||||
out["sigma"] = _to_float_series(out["sigma"], 1)
|
||||
out["p_trunc"] = _to_float_series(out["p_trunc"], 3)
|
||||
out["mu_tilde"] = _to_float_series(out["mu_tilde"], 1)
|
||||
out["mu_delta"] = _to_float_series(out["mu_delta"], 1)
|
||||
out["mu_delta_pct"] = _to_float_series(out["mu_delta_pct"], 1)
|
||||
return out
|
||||
|
||||
|
||||
def _format_table3_backtest_summary(df: pd.DataFrame) -> pd.DataFrame:
|
||||
out = df.copy()
|
||||
out["value"] = out["value"].map(lambda x: round(float(x), 6) if pd.notna(x) else x)
|
||||
out["p_value"] = out["p_value"].map(lambda x: round(float(x), 6) if pd.notna(x) else x)
|
||||
return out
|
||||
|
||||
|
||||
def _format_appendix_site_details(df: pd.DataFrame) -> pd.DataFrame:
|
||||
out = df.copy()
|
||||
out["site_id"] = _to_int_series(out["site_id"])
|
||||
out["mu"] = _to_float_series(out["mu"], 1)
|
||||
out["mu_tilde"] = _to_float_series(out["mu_tilde"], 1)
|
||||
out["k"] = _to_int_series(out["k"])
|
||||
out["annual_service"] = _to_int_series(out["annual_service"])
|
||||
out["r"] = _to_float_series(out["r"], 4)
|
||||
out["quality_factor"] = _to_float_series(out["quality_factor"], 4)
|
||||
out["service_quality_weighted"] = _to_int_series(out["service_quality_weighted"])
|
||||
return out
|
||||
|
||||
|
||||
def export_tables() -> list[Path]:
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
written: list[Path] = []
|
||||
|
||||
# Table 1: overall performance comparison
|
||||
metrics_xlsx = ROOT / "04_metrics.xlsx"
|
||||
metrics = pd.read_excel(metrics_xlsx, sheet_name="metrics_summary")
|
||||
metrics_paper = _format_table1_metrics_summary(metrics)
|
||||
p1 = OUT_DIR / "table1_metrics_summary.csv"
|
||||
metrics_paper.to_csv(p1, index=False, encoding="utf-8-sig")
|
||||
written.append(p1)
|
||||
|
||||
# Table 2: truncation correction (corrected sites)
|
||||
backtest_xlsx = ROOT / "07_backtest.xlsx"
|
||||
corrected = pd.read_excel(backtest_xlsx, sheet_name="corrected_sites")
|
||||
corrected = corrected.copy()
|
||||
corrected["mu_delta"] = corrected["mu_tilde"] - corrected["mu"]
|
||||
corrected["mu_delta_pct"] = corrected["mu_delta"] / corrected["mu"] * 100
|
||||
corrected_paper = _format_table2_corrected_sites(corrected)
|
||||
p2 = OUT_DIR / "table2_corrected_sites.csv"
|
||||
corrected_paper.to_csv(p2, index=False, encoding="utf-8-sig")
|
||||
written.append(p2)
|
||||
|
||||
# Table 3: backtest & fit statistics
|
||||
summary = pd.read_excel(backtest_xlsx, sheet_name="summary_metrics")
|
||||
summary_paper = _format_table3_backtest_summary(summary)
|
||||
p3 = OUT_DIR / "table3_backtest_summary.csv"
|
||||
summary_paper.to_csv(p3, index=False, encoding="utf-8-sig")
|
||||
written.append(p3)
|
||||
|
||||
# Table 4: constraint validation results
|
||||
validate_xlsx = ROOT / "06_validate.xlsx"
|
||||
validation = pd.read_excel(validate_xlsx, sheet_name="validation_results")
|
||||
p4 = OUT_DIR / "table4_validation_results.csv"
|
||||
validation.to_csv(p4, index=False, encoding="utf-8-sig")
|
||||
written.append(p4)
|
||||
|
||||
# Appendix: per-site allocation details (optional for paper appendix)
|
||||
site_details = pd.read_excel(metrics_xlsx, sheet_name="site_details")
|
||||
site_details_paper = _format_appendix_site_details(site_details)
|
||||
p5 = OUT_DIR / "appendix_site_details.csv"
|
||||
site_details_paper.to_csv(p5, index=False, encoding="utf-8-sig")
|
||||
written.append(p5)
|
||||
|
||||
return written
|
||||
|
||||
|
||||
def main() -> None:
|
||||
written = export_tables()
|
||||
rel = [p.relative_to(ROOT) for p in written]
|
||||
print("Wrote:")
|
||||
for p in rel:
|
||||
print(f" - {p}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 180 KiB |
71
task1/paper_tables/appendix_site_details.csv
Normal file
@@ -0,0 +1,71 @@
|
||||
site_id,site_name,mu,mu_tilde,k,annual_service,r,quality_factor,service_quality_weighted
|
||||
1.0,MFP American Legion - Binghamton,200,200,14.0,2803,14.0,1.0,2803
|
||||
2.0,MFP Avoca,315,323,22.0,6921,21.4249,0.7947,5500
|
||||
3.0,MFP Bath,279,279,19.0,5310,19.0,0.8946,4750
|
||||
4.0,MFP Beaver Dams,171,171,12.0,2048,12.0,1.0,2048
|
||||
5.0,MFP Birnie Transportation Services,213,213,15.0,3201,15.0,1.0,3201
|
||||
6.0,MFP Boys and Girls Club,211,211,15.0,3162,15.0,1.0,3162
|
||||
7.0,MFP Bradford,122,122,9.0,1100,9.0,1.0,1100
|
||||
8.0,MFP Campbell,168,168,12.0,2022,12.0,1.0,2022
|
||||
9.0,MFP Canisteo,177,177,13.0,2301,13.0,1.0,2301
|
||||
10.0,MFP Colesville,197,197,14.0,2763,14.0,1.0,2763
|
||||
11.0,MFP College Corning Community College,251,251,18.0,4518,18.0,0.996,4500
|
||||
12.0,MFP College Ithaca College,138,138,10.0,1383,10.0,1.0,1383
|
||||
13.0,MFP College TC3 -College,262,266,19.0,4968,18.686,0.956,4750
|
||||
14.0,MFP Conklin- Maines Community Center,153,153,11.0,1685,11.0,1.0,1685
|
||||
15.0,MFP Danby,160,160,12.0,1923,12.0,1.0,1923
|
||||
16.0,MFP Deposit,157,157,11.0,1722,11.0,1.0,1722
|
||||
17.0,MFP Endwell United Methodist Church,285,289,20.0,5705,19.7173,0.8764,5000
|
||||
18.0,MFP Erin,174,174,13.0,2261,13.0,1.0,2261
|
||||
19.0,MFP First Assembly Of God Church,146,146,11.0,1606,11.0,1.0,1606
|
||||
20.0,MFP Lamphear Court,126,126,9.0,1134,9.0,1.0,1134
|
||||
21.0,MFP Lansing,181,181,13.0,2353,13.0,1.0,2353
|
||||
22.0,MFP Lindley,233,233,16.0,3726,16.0,1.0,3726
|
||||
23.0,MFP Millport,166,166,12.0,1992,12.0,1.0,1992
|
||||
24.0,MFP Montour Falls-Schuyler County Human Services Complex,149,149,11.0,1643,11.0,1.0,1643
|
||||
25.0,MFP Nichols-The Creamery,122,122,9.0,1102,9.0,1.0,1102
|
||||
26.0,MFP Owego VFW,176,176,13.0,2291,13.0,1.0,2291
|
||||
27.0,MFP Prattsburgh,144,144,11.0,1590,11.0,1.0,1590
|
||||
28.0,MFP Rathbone,269,269,19.0,5113,19.0,0.9291,4750
|
||||
29.0,MFP Reach for Christ Church Freeville,220,220,16.0,3520,16.0,1.0,3520
|
||||
30.0,MFP Redeemer Lutheran Church,231,233,16.0,3690,15.8404,1.0,3690
|
||||
31.0,MFP Rehoboth Deliverance Ministry,236,236,17.0,4010,17.0,1.0,4010
|
||||
32.0,MFP Richford,266,266,19.0,5052,19.0,0.9402,4750
|
||||
33.0,MFP Saint Mary Recreation Center,148,148,11.0,1631,11.0,1.0,1631
|
||||
34.0,MFP Salvation Army Ithaca,181,181,13.0,2355,13.0,1.0,2355
|
||||
35.0,MFP Schuyler Outreach,139,139,10.0,1389,10.0,1.0,1389
|
||||
36.0,MFP Senior - Addison Place Apartments,30,30,3.0,90,3.0,1.0,90
|
||||
37.0,MFP Senior - Bragg,67,67,5.0,334,5.0,1.0,334
|
||||
38.0,MFP Senior - Carpenter Apartments,31,31,3.0,93,3.0,1.0,93
|
||||
39.0,MFP Senior - Cayuga Meadows,26,26,3.0,78,3.0,1.0,78
|
||||
40.0,MFP Senior - CFS Lakeview,112,112,8.0,896,8.0,1.0,896
|
||||
41.0,MFP Senior - Conifer Village,34,34,3.0,101,3.0,1.0,101
|
||||
42.0,MFP Senior - Corning Senior Center,75,75,6.0,450,6.0,1.0,450
|
||||
43.0,MFP Senior - Dayspring,77,77,6.0,463,6.0,1.0,463
|
||||
44.0,MFP Senior - East Hill Senior Living,40,40,4.0,159,4.0,1.0,159
|
||||
45.0,"MFP Senior - Elizabeth Square, Waverly",29,29,3.0,87,3.0,1.0,87
|
||||
46.0,MFP Senior - Ellis Hollow,25,25,3.0,74,3.0,1.0,74
|
||||
47.0,MFP Senior - Flannery,62,62,5.0,309,5.0,1.0,309
|
||||
48.0,MFP Senior - Harry L Apartments,33,33,3.0,99,3.0,1.0,99
|
||||
49.0,MFP Senior - Jefferson Village,25,25,3.0,74,3.0,1.0,74
|
||||
50.0,MFP Senior - Lincoln Court,26,26,3.0,78,3.0,1.0,78
|
||||
51.0,MFP Senior - Long Meadow Senior Housing,35,35,3.0,104,3.0,1.0,104
|
||||
52.0,MFP Senior - Metro Plaza Apartments,56,56,5.0,282,5.0,1.0,282
|
||||
53.0,MFP Senior - North Shore Towers,58,58,5.0,292,5.0,1.0,292
|
||||
54.0,"MFP Senior - Northern Broome Senior Center, Whitney Point",51,51,4.0,204,4.0,1.0,204
|
||||
55.0,MFP Senior - Park Terrace Congregate Apartments,24,24,3.0,73,3.0,1.0,73
|
||||
56.0,MFP Senior - Springview Apartments,28,28,3.0,83,3.0,1.0,83
|
||||
57.0,MFP Senior - Titus Towers,73,73,6.0,437,6.0,1.0,437
|
||||
58.0,MFP Senior - Villa Serene,70,70,6.0,418,6.0,1.0,418
|
||||
59.0,MFP Senior - Village Square/Manor,34,34,3.0,103,3.0,1.0,103
|
||||
60.0,MFP Senior - Wells Apartments,24,24,3.0,70,3.0,1.0,70
|
||||
61.0,MFP Senior - Woodsedge Apartments,17,17,2.0,34,2.0,1.0,34
|
||||
62.0,MFP The Love Church,259,259,18.0,4668,18.0,0.964,4500
|
||||
63.0,MFP Troupsburg,149,149,11.0,1636,11.0,1.0,1636
|
||||
64.0,MFP Tuscarora,193,193,14.0,2697,14.0,1.0,2697
|
||||
65.0,MFP Van Etten,214,214,15.0,3206,15.0,1.0,3206
|
||||
66.0,MFP Waverly,397,429,29.0,11502,26.8129,0.6303,7250
|
||||
67.0,MFP Wayland,180,180,13.0,2345,13.0,1.0,2345
|
||||
68.0,MFP Whitney Point,203,203,14.0,2836,14.0,1.0,2836
|
||||
69.0,MFP Windsor,201,201,14.0,2813,14.0,1.0,2813
|
||||
70.0,MFP Woodhull,176,176,13.0,2288,13.0,1.0,2288
|
||||
|
5
task1/paper_tables/table1_metrics_summary.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
method,E1_total_service,E2_quality_weighted,F1_gini,F2_min_satisfaction,F3_cv_satisfaction,E1_total_service_pct,E2_quality_weighted_pct
|
||||
Recommended (μ̃ proportional),139469,131462,0.3137,2.0,0.5603,0,0
|
||||
Baseline 1: Uniform,104797,101309,0.0244,9.2458,0.0486,-25,-23
|
||||
Baseline 2: 2019 Scaled,104071,100264,0.0915,5.0,0.1759,-25,-24
|
||||
Baseline 3: μ proportional (no correction),139129,131397,0.313,2.0,0.5561,0,0
|
||||
|
6
task1/paper_tables/table2_corrected_sites.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
site_id,site_name,mu,sigma,p_trunc,mu_tilde,mu_delta,mu_delta_pct
|
||||
2.0,MFP Avoca,315,57.3497,0.2684,323,8,3.0
|
||||
13.0,MFP College TC3 -College,262,91.9929,0.168,266,4,2.0
|
||||
17.0,MFP Endwell United Methodist Church,285,60.7815,0.1434,289,4,1.0
|
||||
30.0,MFP Redeemer Lutheran Church,231,93.4787,0.1007,233,2,1.0
|
||||
66.0,MFP Waverly,397,51.8754,0.8157,429,32,8.0
|
||||
|
10
task1/paper_tables/table3_backtest_summary.csv
Normal file
@@ -0,0 +1,10 @@
|
||||
metric,value,p_value
|
||||
"corr(visits_2019, μ)",0.0349,0.774
|
||||
"corr(visits_2019, μ̃)",0.0364,0.7645
|
||||
sites_increased,36.0,
|
||||
sites_decreased,32.0,
|
||||
sites_unchanged,2.0,
|
||||
CV(k/μ̃),0.1974,
|
||||
service_2019_actual,102473.0,
|
||||
service_model,139469.0768,
|
||||
improvement_pct,34.6117,
|
||||
|
7
task1/paper_tables/table4_validation_results.csv
Normal file
@@ -0,0 +1,7 @@
|
||||
constraint,formula,expected,actual,passed,details
|
||||
C1: 资源约束,Σk_i = 730,730,730,True,总访问次数 = 730
|
||||
C2: 覆盖约束,k_i >= 1,>= 1,min = 2,True,"最小访问次数 = 2, 违反站点数 = 0"
|
||||
C3: 日容量约束,每日站点数 = 2,所有天 = 2,"min=2, max=2",True,不满足的天数 = 0
|
||||
C4: 无重复约束,site_1 ≠ site_2 (同一天),无重复,重复天数 = 0,True,无
|
||||
C5: 排程一致性,排程次数 = k_i,所有站点一致,不一致站点数 = 0,True,全部一致
|
||||
C6: 总天数,日历天数 = 365,365,365,True,日历包含 365 天
|
||||
|