Upload 2 files
Browse files- app-2.py +162 -0
- requirements-2.txt +3 -0
app-2.py
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import gradio as gr
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
CSV_FILE = "all-vehicles-model@public.csv"
|
| 7 |
+
|
| 8 |
+
# 注诪讜讚讜转 讞砖讜讘讜转 诪转讜讱 讛讚讗讟讛
|
| 9 |
+
COLS = {
|
| 10 |
+
"make": "Make",
|
| 11 |
+
"model": "Model",
|
| 12 |
+
"fuel1": "Fuel Type1",
|
| 13 |
+
"fuel_any": "Fuel Type",
|
| 14 |
+
"drive": "Drive",
|
| 15 |
+
"trans": "Transmission",
|
| 16 |
+
"cyl": "Cylinders",
|
| 17 |
+
"disp": "Engine displacement",
|
| 18 |
+
"mpg_city_f1": "City Mpg For Fuel Type1",
|
| 19 |
+
"mpg_hwy_f1": "Highway Mpg For Fuel Type1",
|
| 20 |
+
"mpg_comb_f1": "Combined Mpg For Fuel Type1",
|
| 21 |
+
"mpg_city_f2": "City Mpg For Fuel Type2",
|
| 22 |
+
"mpg_hwy_f2": "Highway Mpg For Fuel Type2",
|
| 23 |
+
"mpg_comb_f2": "Combined Mpg For Fuel Type2",
|
| 24 |
+
"annual_fuel_cost_f1": "Annual Fuel Cost For Fuel Type1",
|
| 25 |
+
"annual_fuel_cost_f2": "Annual Fuel Cost For Fuel Type2",
|
| 26 |
+
"ev_range_f2": "Epa Range For Fuel Type2",
|
| 27 |
+
"charge_240": "Time to charge at 240V",
|
| 28 |
+
"co2_f1": "Co2 Fuel Type1",
|
| 29 |
+
"co2_tailpipe_f1": "Co2 Tailpipe For Fuel Type1",
|
| 30 |
+
"hatch_lug": "Hatchback luggage volume",
|
| 31 |
+
"hatch_pass": "Hatchback passenger volume",
|
| 32 |
+
"year": "Year"
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
def load_data():
|
| 36 |
+
df = pd.read_csv(CSV_FILE, sep=";", encoding="utf-8", engine="python")
|
| 37 |
+
# 讛诪专讜转 讟讬驻讜住 讘住讬住讬讜转
|
| 38 |
+
for c in ["City Mpg For Fuel Type1", "Highway Mpg For Fuel Type1", "Combined Mpg For Fuel Type1",
|
| 39 |
+
"City Mpg For Fuel Type2", "Highway Mpg For Fuel Type2", "Combined Mpg For Fuel Type2",
|
| 40 |
+
"Annual Fuel Cost For Fuel Type1", "Annual Fuel Cost For Fuel Type2",
|
| 41 |
+
"Epa Range For Fuel Type2", "Time to charge at 240V", "Cylinders", "Engine displacement",
|
| 42 |
+
"Hatchback luggage volume", "Hatchback passenger volume"]:
|
| 43 |
+
if c in df.columns:
|
| 44 |
+
df[c] = pd.to_numeric(df[c], errors="coerce")
|
| 45 |
+
# 讛讜专讚转 讻驻讬诇讜讬讜转 讘住讬住讬转
|
| 46 |
+
keep_cols = [v for v in COLS.values() if v in df.columns]
|
| 47 |
+
subset = [c for c in keep_cols if c in ["Make","Model","Year"]]
|
| 48 |
+
if subset:
|
| 49 |
+
df = df.drop_duplicates(subset=subset)
|
| 50 |
+
return df
|
| 51 |
+
|
| 52 |
+
DF = load_data()
|
| 53 |
+
|
| 54 |
+
def options_safe(col):
|
| 55 |
+
if col in DF.columns:
|
| 56 |
+
vals = DF[col].dropna().astype(str).str.strip().replace("", np.nan).dropna().unique().tolist()
|
| 57 |
+
vals = [v for v in vals if v.lower() not in {"nan","none"}]
|
| 58 |
+
vals.sort()
|
| 59 |
+
return vals[:50]
|
| 60 |
+
return []
|
| 61 |
+
|
| 62 |
+
FUEL_OPTS = sorted(set([*options_safe(COLS["fuel1"]), *options_safe(COLS["fuel_any"]), "No preference"]))
|
| 63 |
+
DRIVE_OPTS = [*options_safe(COLS["drive"]), "No preference"]
|
| 64 |
+
TRANS_OPTS = [*options_safe(COLS["trans"]), "No preference"]
|
| 65 |
+
|
| 66 |
+
def recommend(budget_fuel_per_year, usage, daily_km, seats_min, fuel_pref, drive_pref, trans_pref, cargo_need, perf_pref):
|
| 67 |
+
df = DF.copy()
|
| 68 |
+
|
| 69 |
+
# 住讬谞讜谞讬诐 诇驻讬 讛注讚驻讜转
|
| 70 |
+
if fuel_pref and fuel_pref != "No preference":
|
| 71 |
+
df = df[(df.get(COLS["fuel1"], "").astype(str).str.contains(fuel_pref, case=False, na=False)) |
|
| 72 |
+
(df.get(COLS["fuel_any"], "").astype(str).str.contains(fuel_pref, case=False, na=False))]
|
| 73 |
+
if drive_pref and drive_pref != "No preference" and COLS["drive"] in df.columns:
|
| 74 |
+
df = df[df[COLS["drive"]].astype(str).str.contains(drive_pref, case=False, na=False)]
|
| 75 |
+
if trans_pref and trans_pref != "No preference" and COLS["trans"] in df.columns:
|
| 76 |
+
df = df[df[COLS["trans"]].astype(str).str.contains(trans_pref, case=False, na=False)]
|
| 77 |
+
|
| 78 |
+
def norm(s):
|
| 79 |
+
s = pd.to_numeric(s, errors="coerce")
|
| 80 |
+
return (s - s.min()) / (s.max() - s.min() + 1e-9)
|
| 81 |
+
|
| 82 |
+
# 讬注讬诇讜转 讚诇拽 诇驻讬 砖讬诪讜砖
|
| 83 |
+
if usage == "注讬专":
|
| 84 |
+
eff = df.get(COLS["mpg_city_f1"], df.get(COLS["mpg_comb_f1"]))
|
| 85 |
+
elif usage == "讘讬谞注讬专讜谞讬":
|
| 86 |
+
eff = df.get(COLS["mpg_hwy_f1"], df.get(COLS["mpg_comb_f1"]))
|
| 87 |
+
else:
|
| 88 |
+
eff = df.get(COLS["mpg_comb_f1"])
|
| 89 |
+
eff_score = norm(eff) if eff is not None else pd.Series(0, index=df.index)
|
| 90 |
+
|
| 91 |
+
# 注诇讜转 讚诇拽 砖谞转讬转 谞诪讜讻讛 注讚讬驻讛
|
| 92 |
+
fuel_cost = df.get(COLS["annual_fuel_cost_f1"])
|
| 93 |
+
fuel_cost_score = 1 - norm(fuel_cost) if fuel_cost is not None else pd.Series(0.5, index=df.index)
|
| 94 |
+
|
| 95 |
+
# 讛转讗诪转 EV 诇驻讬 讟讜讜讞 讜谞住讜注讛 讬讜诪讬转
|
| 96 |
+
ev_range = df.get(COLS["ev_range_f2"])
|
| 97 |
+
if ev_range is not None and daily_km:
|
| 98 |
+
ev_ok = (ev_range >= (daily_km * 0.62 * 3)) # 拽"诪 诇诪讬讬诇, 驻讬 3 诪专讜讜讞 讘讬讟讞讜谉
|
| 99 |
+
ev_score = ev_ok.astype(float)
|
| 100 |
+
else:
|
| 101 |
+
ev_score = pd.Series(0.5, index=df.index)
|
| 102 |
+
|
| 103 |
+
# 谞驻讞 诪讟注谉
|
| 104 |
+
cargo = df.get(COLS["hatch_lug"])
|
| 105 |
+
cargo_score = norm(cargo) if (cargo is not None and cargo_need) else pd.Series(0.5, index=df.index)
|
| 106 |
+
|
| 107 |
+
# 讘讬爪讜注讬诐 诪讜诇 讞住讻讜谉 诇驻讬 爪讬诇讬谞讚专讬诐 讜谞驻讞 诪谞讜注
|
| 108 |
+
cyl = df.get(COLS["cyl"]); disp = df.get(COLS["disp"])
|
| 109 |
+
perf_raw = norm(cyl).fillna(0.5) * 0.5 + norm(disp).fillna(0.5) * 0.5
|
| 110 |
+
econ_raw = 1 - perf_raw
|
| 111 |
+
perf_mix = perf_pref * perf_raw + (1 - perf_pref) * econ_raw
|
| 112 |
+
|
| 113 |
+
# 诪砖拽讜诇讜转
|
| 114 |
+
w_eff = 0.3
|
| 115 |
+
w_cost = 0.25
|
| 116 |
+
w_ev = 0.15
|
| 117 |
+
w_cargo = 0.1
|
| 118 |
+
w_perf = 0.2
|
| 119 |
+
|
| 120 |
+
score = w_eff*eff_score.fillna(0.5) + w_cost*fuel_cost_score.fillna(0.5) + w_ev*ev_score.fillna(0.5) + \
|
| 121 |
+
w_cargo*cargo_score.fillna(0.5) + w_perf*perf_mix.fillna(0.5)
|
| 122 |
+
|
| 123 |
+
df_out = df.copy()
|
| 124 |
+
df_out["Score"] = score.round(4)
|
| 125 |
+
show_cols = [c for c in [
|
| 126 |
+
COLS["make"], COLS["model"], "Year" if "Year" in df.columns else None,
|
| 127 |
+
COLS["fuel1"] if COLS["fuel1"] in df.columns else COLS["fuel_any"],
|
| 128 |
+
COLS["drive"], COLS["trans"],
|
| 129 |
+
COLS["mpg_city_f1"], COLS["mpg_hwy_f1"], COLS["mpg_comb_f1"],
|
| 130 |
+
COLS["annual_fuel_cost_f1"], COLS["ev_range_f2"],
|
| 131 |
+
COLS["cyl"], COLS["disp"],
|
| 132 |
+
"Score"
|
| 133 |
+
] if (c and (c in df.columns)) or c=="Score"]
|
| 134 |
+
|
| 135 |
+
return df_out.sort_values("Score", ascending=False).head(10)[show_cols]
|
| 136 |
+
|
| 137 |
+
with gr.Blocks(title="诪诪诇讬抓 专讻讘讬诐") as demo:
|
| 138 |
+
gr.Markdown("# 诪诪诇讬抓 专讻讘讬诐 讞讻诐\n讛讗驻诇讬拽爪讬讛 诪转讗讬诪讛 讚讙诪讬诐 诇爪专讻讬诐 砖诇讱 注诇 讘住讬住 讚讗讟讛 砖诇 EPA.\n")
|
| 139 |
+
|
| 140 |
+
with gr.Row():
|
| 141 |
+
usage = gr.Radio(["注讬专", "讘讬谞注讬专讜谞讬", "诪注讜专讘"], value="诪注讜专讘", label="讗讜驻讬 砖讬诪讜砖")
|
| 142 |
+
daily_km = gr.Slider(0, 200, value=30, step=5, label="谞住讜注讛 讬讜诪讬转 诪诪讜爪注转 讘拽讬诇讜诪讟专讬诐")
|
| 143 |
+
budget_fuel = gr.Slider(0, 6000, value=3000, step=100, label="转拽爪讬讘 讚诇拽 讗讜 讞砖诪诇 砖谞转讬")
|
| 144 |
+
|
| 145 |
+
with gr.Row():
|
| 146 |
+
fuel_pref = gr.Dropdown(choices=FUEL_OPTS, value="No preference", label="注讚讬驻讜转 诇住讜讙 讚诇拽")
|
| 147 |
+
drive_pref = gr.Dropdown(choices=DRIVE_OPTS, value="No preference", label="讛谞注讛")
|
| 148 |
+
trans_pref = gr.Dropdown(choices=TRANS_OPTS, value="No preference", label="转讬讘转 讛讬诇讜讻讬诐")
|
| 149 |
+
|
| 150 |
+
with gr.Row():
|
| 151 |
+
cargo_need = gr.Slider(0, 800, value=0, step=20, label="谞驻讞 诪讟注谉 诪讬谞讬诪诇讬 专爪讜讬")
|
| 152 |
+
perf_pref = gr.Slider(0, 1, value=0.4, step=0.05, label="注讚讬驻讜转 0 讞住讻讜谉 1 讘讬爪讜注讬诐")
|
| 153 |
+
seats_min = gr.Slider(2, 8, value=4, step=1, label="诪讜砖讘讬诐 诪讬谞讬诪讜诐")
|
| 154 |
+
|
| 155 |
+
btn = gr.Button("诪爪讗 专讻讘讬诐")
|
| 156 |
+
out = gr.Dataframe(interactive=False, wrap=True, label="讛转讗诪讜转 诪讜诪诇爪讜转 . 讟讜驻 10")
|
| 157 |
+
|
| 158 |
+
btn.click(fn=recommend,
|
| 159 |
+
inputs=[budget_fuel, usage, daily_km, seats_min, fuel_pref, drive_pref, trans_pref, cargo_need, perf_pref],
|
| 160 |
+
outputs=out)
|
| 161 |
+
|
| 162 |
+
demo.queue().launch()
|
requirements-2.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
pandas
|
| 3 |
+
numpy
|