from pathlib import Path import gradio as gr import joblib import matplotlib.pyplot as plt import numpy as np import pandas as pd from sklearn.metrics import mean_squared_error, r2_score DATA_PATH = Path(__file__).with_name("Fuel_Consumption_2000-2022.csv") MODEL_PATH = Path(__file__).with_name("best_model.joblib") TARGET = "CO2 Emissions(g/km)" NUMERIC_FEATURES = [ "Engine Size(L)", "Cylinders", "Fuel Consumption Comb (L/100 km)", ] CATEGORICAL_FEATURES = [ "Vehicle Class", "Fuel Type", ] MODEL_FEATURES = NUMERIC_FEATURES + CATEGORICAL_FEATURES def load_dataset() -> pd.DataFrame: df = pd.read_csv(DATA_PATH) df["Make"] = df["Make"].apply(lambda v: v.upper()) df["Vehicle Class"] = df["Vehicle Class"].apply( lambda v: v.upper().replace(": ", " - ") ) return df[MODEL_FEATURES + [TARGET]].copy() def load_metrics() -> tuple[pd.DataFrame, dict]: df = load_dataset() artifact = joblib.load(MODEL_PATH) y_pred = artifact["holdout_prediction"] y_test = artifact["y_test"] metrics = { "Test RMSE": round(mean_squared_error(y_test, y_pred) ** 0.5, 3), "Test R2": round(r2_score(y_test, y_pred), 4), "Train rows": int(artifact["train_rows"]), "Test rows": int(artifact["test_rows"]), } return df, metrics ARTIFACT = joblib.load(MODEL_PATH) MODEL = ARTIFACT["model"] DATAFRAME, METRICS = load_metrics() VEHICLE_CLASSES = sorted(DATAFRAME["Vehicle Class"].dropna().unique().tolist()) FUEL_TYPES = sorted(DATAFRAME["Fuel Type"].dropna().unique().tolist()) CYLINDER_VALUES = sorted(int(v) for v in DATAFRAME["Cylinders"].dropna().unique().tolist()) ENGINE_MIN = float(DATAFRAME["Engine Size(L)"].min()) ENGINE_MAX = float(DATAFRAME["Engine Size(L)"].max()) FUEL_MIN = float(DATAFRAME["Fuel Consumption Comb (L/100 km)"].min()) FUEL_MAX = float(DATAFRAME["Fuel Consumption Comb (L/100 km)"].max()) def build_relationship_plot(): plot_df = DATAFRAME[ [ "Fuel Consumption Comb (L/100 km)", TARGET, "Fuel Type", ] ].dropna() fuel_types = sorted(plot_df["Fuel Type"].unique().tolist()) cmap = plt.get_cmap("tab10") fig, ax = plt.subplots(figsize=(8, 5)) for index, fuel in enumerate(fuel_types): subset = plot_df[plot_df["Fuel Type"] == fuel] ax.scatter( subset["Fuel Consumption Comb (L/100 km)"], subset[TARGET], s=28, alpha=0.55, color=cmap(index % 10), label=fuel, ) trend_x = plot_df["Fuel Consumption Comb (L/100 km)"] trend_y = plot_df[TARGET] line_coef = np.polyfit(trend_x, trend_y, 1) line_x = pd.Series([trend_x.min(), trend_x.max()]) line_y = line_coef[0] * line_x + line_coef[1] ax.plot(line_x, line_y, color="#222222", linewidth=2, label="Trend line") ax.set_title("Fuel Consumption vs CO2 Emissions") ax.set_xlabel("Fuel Consumption Comb (L/100 km)") ax.set_ylabel("CO2 Emissions (g/km)") ax.set_facecolor("#fafafa") ax.grid(alpha=0.2, linestyle="--", linewidth=0.6) ax.legend(title="Fuel Type", fontsize=8) fig.tight_layout() return fig def build_vehicle_class_plot(): class_df = ( DATAFRAME.groupby("Vehicle Class", as_index=False)[TARGET] .mean() .sort_values(TARGET, ascending=False) .head(10) ) fig, ax = plt.subplots(figsize=(8, 5)) ax.barh(class_df["Vehicle Class"], class_df[TARGET], color="#2a9d8f") ax.invert_yaxis() ax.set_title("Top 10 Vehicle Classes by Average CO2 Emissions") ax.set_xlabel("Average CO2 Emissions (g/km)") ax.set_ylabel("Vehicle Class") ax.set_facecolor("#fafafa") ax.grid(axis="x", alpha=0.2, linestyle="--", linewidth=0.6) fig.tight_layout() return fig def build_emissions_distribution_plot(): fig, ax = plt.subplots(figsize=(8, 5)) ax.hist(DATAFRAME[TARGET].dropna(), bins=30, color="#f4a261", edgecolor="white") ax.set_title("Distribution of CO2 Emissions") ax.set_xlabel("CO2 Emissions (g/km)") ax.set_ylabel("Frequency") ax.set_facecolor("#fafafa") ax.grid(axis="y", alpha=0.2, linestyle="--", linewidth=0.6) fig.tight_layout() return fig def build_engine_size_plot(): plot_df = DATAFRAME[["Engine Size(L)", TARGET]].dropna() fig, ax = plt.subplots(figsize=(8, 5)) ax.scatter( plot_df["Engine Size(L)"], plot_df[TARGET], alpha=0.6, color="#457b9d", s=30, ) ax.set_title("Engine Size vs CO2 Emissions") ax.set_xlabel("Engine Size(L)") ax.set_ylabel("CO2 Emissions(g/km)") ax.set_facecolor("#fafafa") ax.grid(alpha=0.2, linestyle="--", linewidth=0.6) fig.tight_layout() return fig def predict_co2_emission( engine_size: float, cylinders: int, fuel_consumption_comb: float, vehicle_class: str, fuel_type: str, ) -> tuple[float, str]: sample = pd.DataFrame( { "Engine Size(L)": [engine_size], "Cylinders": [cylinders], "Fuel Consumption Comb (L/100 km)": [fuel_consumption_comb], "Vehicle Class": [vehicle_class], "Fuel Type": [fuel_type], } ) prediction = float(MODEL.predict(sample)[0]) details = ( "Model 3 - Parsimonious Mixed\n" f"Engine Size(L): {engine_size}\n" f"Cylinders: {cylinders}\n" f"Fuel Consumption Comb (L/100 km): {fuel_consumption_comb}\n" f"Vehicle Class: {vehicle_class}\n" f"Fuel Type: {fuel_type}\n" f"Estimated CO2: {prediction:.2f} g/km" ) return round(prediction, 2), details DESCRIPTION = f""" # CO2 Emissions Predictor This app predicts **CO2 emissions** for a vehicle. It uses the following inputs: - Engine Size(L) - Cylinders - Fuel Consumption Comb (L/100 km) - Vehicle Class - Fuel Type Model performance on test data: - Test RMSE: {METRICS["Test RMSE"]} - Test R2: {METRICS["Test R2"]} The charts below help show simple patterns in the dataset. """ with gr.Blocks(title="CO2 Emissions Predictor") as demo: gr.Markdown(DESCRIPTION) with gr.Row(): engine_size = gr.Slider( minimum=ENGINE_MIN, maximum=ENGINE_MAX, value=2.0, step=0.1, label="Engine Size(L)", ) cylinders = gr.Dropdown( choices=CYLINDER_VALUES, value=4, label="Cylinders", ) with gr.Row(): fuel_consumption = gr.Slider( minimum=FUEL_MIN, maximum=FUEL_MAX, value=7.5, step=0.1, label="Fuel Consumption Comb (L/100 km)", ) vehicle_class = gr.Dropdown( choices=VEHICLE_CLASSES, value="COMPACT" if "COMPACT" in VEHICLE_CLASSES else VEHICLE_CLASSES[0], label="Vehicle Class", ) fuel_type = gr.Dropdown( choices=FUEL_TYPES, value="X" if "X" in FUEL_TYPES else FUEL_TYPES[0], label="Fuel Type", ) predict_button = gr.Button("Predict") prediction = gr.Number(label="Predicted CO2 (g/km)") summary = gr.Textbox(label="Result Summary", lines=7) predict_button.click( fn=predict_co2_emission, inputs=[ engine_size, cylinders, fuel_consumption, vehicle_class, fuel_type, ], outputs=[prediction, summary], ) gr.Markdown("## Charts") gr.Markdown( "- Distribution of CO2 emissions across the dataset.\n" "- Relationship between fuel consumption and CO2 emissions.\n" "- Relationship between engine size and CO2 emissions.\n" "- Vehicle classes with the highest average CO2 emissions." ) with gr.Row(): gr.Plot( value=build_emissions_distribution_plot, label="Distribution of CO2 Emissions", ) gr.Plot( value=build_relationship_plot, label="Fuel Consumption vs CO2 Emissions", ) with gr.Row(): gr.Plot( value=build_engine_size_plot, label="Engine Size vs CO2 Emissions", ) gr.Plot( value=build_vehicle_class_plot, label="Top Vehicle Classes by CO2 Emissions", ) gr.Examples( examples=[ [2.0, 4, 7.5, "COMPACT", "X"], [3.5, 6, 10.8, "SUV - SMALL", "X"], [5.0, 8, 14.2, "PICKUP TRUCK - STANDARD", "Z"], ], inputs=[ engine_size, cylinders, fuel_consumption, vehicle_class, fuel_type, ], outputs=[prediction, summary], fn=predict_co2_emission, cache_examples=False, ) if __name__ == "__main__": demo.launch()