import gradio as gr import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler # --- Sample Morningstar-style data --- data = { "5Y_Return": [14.0, 7.5, 13.2, 6.0, 15.0, 8.0, 12.0, 6.5, 10.5, 7.2], "Volatility": [8.0, 6.5, 7.8, 9.0, 7.0, 6.2, 7.1, 8.5, 6.8, 7.9], "Risk_Score": [2, 3, 2, 4, 1, 3, 2, 4, 2, 3], "Rating": ["Good", "Bad", "Good", "Bad", "Good", "Bad", "Good", "Bad", "Good", "Bad"] } df = pd.DataFrame(data) df["Label"] = df["Rating"].map({"Good": 1, "Bad": 0}) # --- Train full SVM model for prediction --- X = df[["5Y_Return", "Volatility", "Risk_Score"]] y = df["Label"] scaler = StandardScaler() X_scaled = scaler.fit_transform(X) model = SVC(kernel="linear", probability=True) model.fit(X_scaled, y) # --- Function to classify and plot 2D SVM boundary --- def classify_and_plot(return_5y, volatility, risk_score): # Predict input_data = [[return_5y, volatility, risk_score]] input_scaled = scaler.transform(input_data) prediction = model.predict(input_scaled)[0] confidence = model.predict_proba(input_scaled)[0][prediction] result = "Good Investment" if prediction == 1 else "Bad Investment" # For plotting, use only 2D X_2d = df[["5Y_Return", "Volatility"]].values y_2d = df["Label"].values scaler_2d = StandardScaler() X_2d_scaled = scaler_2d.fit_transform(X_2d) model_2d = SVC(kernel="linear") model_2d.fit(X_2d_scaled, y_2d) # Plot decision boundary fig, ax = plt.subplots(figsize=(6, 5)) ax.scatter(X_2d_scaled[:, 0], X_2d_scaled[:, 1], c=y_2d, cmap="bwr", edgecolors="k", s=60) # Support vectors ax.scatter(model_2d.support_vectors_[:, 0], model_2d.support_vectors_[:, 1], s=150, facecolors='none', edgecolors='k', linewidths=1.5, label="Support Vectors") # Decision boundary xlim = ax.get_xlim() ylim = ax.get_ylim() xx = np.linspace(xlim[0], xlim[1], 30) yy = np.linspace(ylim[0], ylim[1], 30) YY, XX = np.meshgrid(yy, xx) xy = np.vstack([XX.ravel(), YY.ravel()]).T Z = model_2d.decision_function(xy).reshape(XX.shape) ax.contour(XX, YY, Z, colors='k', levels=[-1, 0, 1], alpha=0.7, linestyles=['--', '-', '--']) # Annotations ax.set_title("SVM Decision Boundary (2 Features)") ax.set_xlabel("5Y Return (scaled)") ax.set_ylabel("Volatility (scaled)") ax.legend() ax.grid(True) # Save and return image plot_path = "/tmp/svm_plot.png" fig.savefig(plot_path) plt.close(fig) return f"{result} (Confidence: {confidence:.2f})", plot_path # --- Gradio UI --- with gr.Blocks() as demo: gr.Markdown("## 🧠 SVM Classifier: Mutual Fund Recommendation") with gr.Row(): return_input = gr.Number(label="5-Year Return (%)", value=10.0) vol_input = gr.Number(label="Volatility (%)", value=7.0) risk_input = gr.Number(label="Risk Score (1=Low, 5=High)", value=3) classify_btn = gr.Button("Classify and Show Decision Boundary") output_label = gr.Textbox(label="Prediction") gr.Markdown("""### 📊 Benchmark Guide **🔴 Blue Dots = Good Investments** **🔴 Red Dots = Bad Investments** **⚫ Solid Black Line = Decision Boundary** **⚫ Dashed Lines = Margins (distance to support vectors)** **⭕ Large Hollow Dots = Support Vectors (key data points)** """) output_plot = gr.Image(label="SVM Decision Boundary") classify_btn.click( fn=classify_and_plot, inputs=[return_input, vol_input, risk_input], outputs=[output_label, output_plot] ) if __name__ == "__main__": demo.launch()