From 83370602b0f1af31f48f14cb9a3475b30f8f04ee Mon Sep 17 00:00:00 2001 From: NirviMathur Date: Mon, 13 Oct 2025 14:36:51 +0530 Subject: [PATCH 1/5] Added SVM classifier and regressor with Streamlit visualization --- models/svm.py | 42 ++++++++++++++++++++++++++++++++++ pages/svm.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 models/svm.py create mode 100644 pages/svm.py diff --git a/models/svm.py b/models/svm.py new file mode 100644 index 0000000..fbd5d1c --- /dev/null +++ b/models/svm.py @@ -0,0 +1,42 @@ +import numpy as np +from sklearn import datasets +from sklearn.model_selection import train_test_split +from sklearn.svm import SVC, SVR +from sklearn.metrics import accuracy_score, mean_squared_error + +class SVMClassifier: + def __init__(self, kernel='linear', C=1.0): + self.kernel = kernel + self.C = C + self.model = SVC(kernel=self.kernel, C=self.C) + + def train(self, X, y): + self.model.fit(X, y) + + def predict(self, X): + return self.model.predict(X) + + def evaluate(self, X, y): + y_pred = self.predict(X) + return accuracy_score(y, y_pred) + + def get_support_vectors(self): + return self.model.support_vectors_ + + +class SVMRegressor: + def __init__(self, kernel='rbf', C=1.0, epsilon=0.1): + self.kernel = kernel + self.C = C + self.epsilon = epsilon + self.model = SVR(kernel=self.kernel, C=self.C, epsilon=self.epsilon) + + def train(self, X, y): + self.model.fit(X, y) + + def predict(self, X): + return self.model.predict(X) + + def evaluate(self, X, y): + y_pred = self.predict(X) + return mean_squared_error(y, y_pred, squared=False) # RMSE diff --git a/pages/svm.py b/pages/svm.py new file mode 100644 index 0000000..4c1cefc --- /dev/null +++ b/pages/svm.py @@ -0,0 +1,62 @@ +import streamlit as st +import numpy as np +import matplotlib.pyplot as plt +from sklearn import datasets +from models.svm import SVMClassifier, SVMRegressor + +st.title("🔷 Support Vector Machine (SVM) Simulator") + +option = st.radio("Choose Mode", ["Classification", "Regression"]) + +if option == "Classification": + st.subheader("SVM Classifier Visualization") + + # Load toy dataset + X, y = datasets.make_blobs(n_samples=100, centers=2, random_state=6, cluster_std=1.2) + + kernel = st.selectbox("Kernel", ["linear", "poly", "rbf", "sigmoid"]) + C = st.slider("Regularization (C)", 0.01, 10.0, 1.0) + + model = SVMClassifier(kernel=kernel, C=C) + model.train(X, y) + + # Plot decision boundary + x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 + y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 + xx, yy = np.meshgrid(np.linspace(x_min, x_max, 300), + np.linspace(y_min, y_max, 300)) + Z = model.predict(np.c_[xx.ravel(), yy.ravel()]) + Z = Z.reshape(xx.shape) + + plt.figure(figsize=(8, 6)) + plt.contourf(xx, yy, Z, cmap='coolwarm', alpha=0.6) + plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm', edgecolors='k') + plt.scatter(model.get_support_vectors()[:, 0], model.get_support_vectors()[:, 1], + s=100, facecolors='none', edgecolors='yellow', label='Support Vectors') + plt.legend() + st.pyplot(plt) + st.write(f"**Accuracy:** {model.evaluate(X, y):.2f}") + +else: + st.subheader("SVM Regressor Visualization") + + # Generate regression dataset + X = np.sort(5 * np.random.rand(100, 1), axis=0) + y = np.sin(X).ravel() + np.random.randn(100) * 0.1 + + kernel = st.selectbox("Kernel", ["linear", "poly", "rbf", "sigmoid"]) + C = st.slider("Regularization (C)", 0.1, 10.0, 1.0) + epsilon = st.slider("Epsilon", 0.01, 1.0, 0.1) + + model = SVMRegressor(kernel=kernel, C=C, epsilon=epsilon) + model.train(X, y) + y_pred = model.predict(X) + + # Plot regression curve + plt.figure(figsize=(8, 6)) + plt.scatter(X, y, color="blue", label="Data") + plt.plot(X, y_pred, color="red", label="SVM Prediction") + plt.title("SVM Regression") + plt.legend() + st.pyplot(plt) + st.write(f"**RMSE:** {model.evaluate(X, y):.3f}") From aed7e01d9c764483c0f3bc1a46c3b1aeb3c7d389 Mon Sep 17 00:00:00 2001 From: NirviMathur Date: Mon, 13 Oct 2025 14:43:27 +0530 Subject: [PATCH 2/5] Added plot_roc_curve helper to generate ROC curve for Streamlit visualization --- pages/LogisticRegression.py | 6 +++++ utils/plot_helpers.py | 54 +++++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 23 deletions(-) create mode 100644 pages/LogisticRegression.py diff --git a/pages/LogisticRegression.py b/pages/LogisticRegression.py new file mode 100644 index 0000000..d0decec --- /dev/null +++ b/pages/LogisticRegression.py @@ -0,0 +1,6 @@ +from utils.plot_helpers import plot_roc_curve +import streamlit as st + +# Example +fig = plot_roc_curve(y_true, y_pred_proba) +st.pyplot(fig) diff --git a/utils/plot_helpers.py b/utils/plot_helpers.py index c20d604..f8393c1 100644 --- a/utils/plot_helpers.py +++ b/utils/plot_helpers.py @@ -1,28 +1,36 @@ import matplotlib.pyplot as plt import seaborn as sns -from sklearn.metrics import confusion_matrix, roc_curve, auc - -def plot_regression_line(X, y, model): - plt.figure() - plt.scatter(X, y, color="blue", label="Data") - y_pred = model.predict(X) - plt.plot(X, y_pred, color="red", label="Prediction") - plt.legend() - return plt - -def plot_confusion_matrix(y_true, y_pred, labels): - cm = confusion_matrix(y_true, y_pred) - plt.figure() - sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", xticklabels=labels, yticklabels=labels) - plt.xlabel("Predicted") - plt.ylabel("Actual") - return plt +from sklearn.metrics import roc_curve, auc def plot_roc_curve(y_true, y_scores): - fpr, tpr, _ = roc_curve(y_true, y_scores) + """ + Plots the ROC curve given true labels and predicted scores. + + Parameters: + y_true (array-like): Ground truth binary labels (0 or 1) + y_scores (array-like): Predicted probabilities or decision scores + + Returns: + fig (matplotlib.figure.Figure): The ROC curve figure object + """ + + # Compute ROC curve and AUC + fpr, tpr, thresholds = roc_curve(y_true, y_scores) roc_auc = auc(fpr, tpr) - plt.figure() - plt.plot(fpr, tpr, label=f"AUC = {roc_auc:.2f}") - plt.plot([0, 1], [0, 1], linestyle="--") - plt.legend() - return plt + + # Create a figure + fig, ax = plt.subplots(figsize=(6, 5)) + sns.set_style("whitegrid") + + ax.plot(fpr, tpr, color="blue", lw=2, label=f"ROC Curve (AUC = {roc_auc:.2f})") + ax.plot([0, 1], [0, 1], color="gray", lw=1.5, linestyle="--", label="Random Guess") + + ax.set_title("Receiver Operating Characteristic (ROC) Curve", fontsize=12) + ax.set_xlabel("False Positive Rate", fontsize=10) + ax.set_ylabel("True Positive Rate", fontsize=10) + ax.legend(loc="lower right") + ax.set_xlim([0.0, 1.0]) + ax.set_ylim([0.0, 1.05]) + + plt.tight_layout() + return fig From f118f27179c33c034916c06a9b30e5c90f975b9d Mon Sep 17 00:00:00 2001 From: NirviMathur Date: Mon, 13 Oct 2025 14:51:25 +0530 Subject: [PATCH 3/5] Enhanced plot_confusion_matrix with annotations, labels, and color customization --- models/svm.py | 45 ++++--------------------------------------- utils/plot_helpers.py | 45 ++++++++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 61 deletions(-) diff --git a/models/svm.py b/models/svm.py index fbd5d1c..135d910 100644 --- a/models/svm.py +++ b/models/svm.py @@ -1,42 +1,5 @@ -import numpy as np -from sklearn import datasets -from sklearn.model_selection import train_test_split -from sklearn.svm import SVC, SVR -from sklearn.metrics import accuracy_score, mean_squared_error +from utils.plot_helpers import plot_confusion_matrix +import streamlit as st -class SVMClassifier: - def __init__(self, kernel='linear', C=1.0): - self.kernel = kernel - self.C = C - self.model = SVC(kernel=self.kernel, C=self.C) - - def train(self, X, y): - self.model.fit(X, y) - - def predict(self, X): - return self.model.predict(X) - - def evaluate(self, X, y): - y_pred = self.predict(X) - return accuracy_score(y, y_pred) - - def get_support_vectors(self): - return self.model.support_vectors_ - - -class SVMRegressor: - def __init__(self, kernel='rbf', C=1.0, epsilon=0.1): - self.kernel = kernel - self.C = C - self.epsilon = epsilon - self.model = SVR(kernel=self.kernel, C=self.C, epsilon=self.epsilon) - - def train(self, X, y): - self.model.fit(X, y) - - def predict(self, X): - return self.model.predict(X) - - def evaluate(self, X, y): - y_pred = self.predict(X) - return mean_squared_error(y, y_pred, squared=False) # RMSE +fig = plot_confusion_matrix(y_true, y_pred, labels=["Class 0", "Class 1"], cmap="Purples") +st.pyplot(fig) diff --git a/utils/plot_helpers.py b/utils/plot_helpers.py index f8393c1..6dd2a55 100644 --- a/utils/plot_helpers.py +++ b/utils/plot_helpers.py @@ -1,36 +1,41 @@ import matplotlib.pyplot as plt import seaborn as sns -from sklearn.metrics import roc_curve, auc +from sklearn.metrics import confusion_matrix -def plot_roc_curve(y_true, y_scores): +def plot_confusion_matrix(y_true, y_pred, labels=None, annotate=True, cmap="Blues"): """ - Plots the ROC curve given true labels and predicted scores. + Plots a customizable confusion matrix. Parameters: - y_true (array-like): Ground truth binary labels (0 or 1) - y_scores (array-like): Predicted probabilities or decision scores + y_true (array-like): Ground truth labels. + y_pred (array-like): Predicted labels. + labels (list, optional): Class names to display on axes. + annotate (bool): Whether to show cell values. + cmap (str): Colormap for heatmap (e.g. 'Blues', 'Greens', 'Oranges'). Returns: - fig (matplotlib.figure.Figure): The ROC curve figure object + fig (matplotlib.figure.Figure): The confusion matrix figure. """ - # Compute ROC curve and AUC - fpr, tpr, thresholds = roc_curve(y_true, y_scores) - roc_auc = auc(fpr, tpr) - - # Create a figure + cm = confusion_matrix(y_true, y_pred) fig, ax = plt.subplots(figsize=(6, 5)) sns.set_style("whitegrid") - ax.plot(fpr, tpr, color="blue", lw=2, label=f"ROC Curve (AUC = {roc_auc:.2f})") - ax.plot([0, 1], [0, 1], color="gray", lw=1.5, linestyle="--", label="Random Guess") - - ax.set_title("Receiver Operating Characteristic (ROC) Curve", fontsize=12) - ax.set_xlabel("False Positive Rate", fontsize=10) - ax.set_ylabel("True Positive Rate", fontsize=10) - ax.legend(loc="lower right") - ax.set_xlim([0.0, 1.0]) - ax.set_ylim([0.0, 1.05]) + sns.heatmap( + cm, + annot=annotate, + fmt="d" if annotate else "", + cmap=cmap, + cbar=False, + xticklabels=labels if labels is not None else "auto", + yticklabels=labels if labels is not None else "auto", + linewidths=0.5, + ax=ax, + ) + + ax.set_xlabel("Predicted Labels", fontsize=11) + ax.set_ylabel("True Labels", fontsize=11) + ax.set_title("Confusion Matrix", fontsize=13, pad=12) plt.tight_layout() return fig From b04990f3e6b33ce6538b70a7c866e814b5090a3e Mon Sep 17 00:00:00 2001 From: NirviMathur Date: Mon, 13 Oct 2025 15:00:09 +0530 Subject: [PATCH 4/5] Added KNN classifier/regressor with Streamlit visualization and adjustable k --- models/knn.py | 33 ++++++++++++++++++++++++++ pages/KNN.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 models/knn.py create mode 100644 pages/KNN.py diff --git a/models/knn.py b/models/knn.py new file mode 100644 index 0000000..de6171d --- /dev/null +++ b/models/knn.py @@ -0,0 +1,33 @@ +from sklearn.neighbors import KNeighborsClassifier, KNeighborsRegressor +from sklearn.metrics import accuracy_score, mean_squared_error + +class KNNClassifier: + def __init__(self, n_neighbors=3): + self.n_neighbors = n_neighbors + self.model = KNeighborsClassifier(n_neighbors=self.n_neighbors) + + def train(self, X, y): + self.model.fit(X, y) + + def predict(self, X): + return self.model.predict(X) + + def evaluate(self, X, y): + y_pred = self.predict(X) + return accuracy_score(y, y_pred) + + +class KNNRegressor: + def __init__(self, n_neighbors=3): + self.n_neighbors = n_neighbors + self.model = KNeighborsRegressor(n_neighbors=self.n_neighbors) + + def train(self, X, y): + self.model.fit(X, y) + + def predict(self, X): + return self.model.predict(X) + + def evaluate(self, X, y): + y_pred = self.predict(X) + return mean_squared_error(y, y_pred, squared=False) # RMSE diff --git a/pages/KNN.py b/pages/KNN.py new file mode 100644 index 0000000..163d2de --- /dev/null +++ b/pages/KNN.py @@ -0,0 +1,66 @@ +import streamlit as st +import numpy as np +import matplotlib.pyplot as plt +from sklearn import datasets +from models.knn import KNNClassifier, KNNRegressor +from utils.plot_helpers import plot_confusion_matrix + +st.title("🧩 K-Nearest Neighbors (KNN) Simulator") + +mode = st.radio("Choose Mode", ["Classification", "Regression"]) + +if mode == "Classification": + st.subheader("KNN Classifier Visualization") + + # Load dataset + X, y = datasets.make_classification( + n_samples=150, n_features=2, n_informative=2, n_redundant=0, + n_clusters_per_class=1, random_state=42 + ) + + k = st.slider("Number of Neighbors (k)", 1, 15, 3) + model = KNNClassifier(n_neighbors=k) + model.train(X, y) + y_pred = model.predict(X) + + # Decision boundary + x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 + y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 + xx, yy = np.meshgrid(np.linspace(x_min, x_max, 300), + np.linspace(y_min, y_max, 300)) + Z = model.predict(np.c_[xx.ravel(), yy.ravel()]) + Z = Z.reshape(xx.shape) + + plt.figure(figsize=(8, 6)) + plt.contourf(xx, yy, Z, cmap="coolwarm", alpha=0.5) + plt.scatter(X[:, 0], X[:, 1], c=y, cmap="coolwarm", edgecolors="k") + plt.title(f"KNN Classifier (k={k})") + st.pyplot(plt) + + st.write(f"**Accuracy:** {model.evaluate(X, y):.2f}") + + # Confusion matrix + fig = plot_confusion_matrix(y, y_pred, labels=["Class 0", "Class 1"], cmap="Purples") + st.pyplot(fig) + +else: + st.subheader("KNN Regressor Visualization") + + # Generate regression dataset + X = np.linspace(0, 10, 100).reshape(-1, 1) + y = np.sin(X).ravel() + np.random.randn(100) * 0.1 + + k = st.slider("Number of Neighbors (k)", 1, 15, 3) + model = KNNRegressor(n_neighbors=k) + model.train(X, y) + y_pred = model.predict(X) + + # Plot regression + plt.figure(figsize=(8, 6)) + plt.scatter(X, y, color="blue", label="Data") + plt.plot(X, y_pred, color="red", label=f"KNN Prediction (k={k})") + plt.title("KNN Regression") + plt.legend() + st.pyplot(plt) + + st.write(f"**RMSE:** {model.evaluate(X, y):.3f}") From 092eba1a0bcd19f6d56c4ba3416c5b1ae1746f3d Mon Sep 17 00:00:00 2001 From: NirviMathur Date: Mon, 13 Oct 2025 15:04:40 +0530 Subject: [PATCH 5/5] Added Decision Tree classifier/regressor with Streamlit visualization and dataset helpers --- models/decision_tree.py | 35 ++++++++++++++++++++++ pages/Decision_Tree.py | 65 +++++++++++++++++++++++++++++++++++++++++ utils/data_helpers.py | 40 ++++++++----------------- 3 files changed, 112 insertions(+), 28 deletions(-) create mode 100644 models/decision_tree.py create mode 100644 pages/Decision_Tree.py diff --git a/models/decision_tree.py b/models/decision_tree.py new file mode 100644 index 0000000..eabb0b6 --- /dev/null +++ b/models/decision_tree.py @@ -0,0 +1,35 @@ +from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor +from sklearn.metrics import accuracy_score, mean_squared_error + +class DecisionTreeModelClassifier: + def __init__(self, max_depth=None, criterion="gini"): + self.max_depth = max_depth + self.criterion = criterion + self.model = DecisionTreeClassifier(max_depth=self.max_depth, criterion=self.criterion) + + def train(self, X, y): + self.model.fit(X, y) + + def predict(self, X): + return self.model.predict(X) + + def evaluate(self, X, y): + y_pred = self.predict(X) + return accuracy_score(y, y_pred) + + +class DecisionTreeModelRegressor: + def __init__(self, max_depth=None, criterion="squared_error"): + self.max_depth = max_depth + self.criterion = criterion + self.model = DecisionTreeRegressor(max_depth=self.max_depth, criterion=self.criterion) + + def train(self, X, y): + self.model.fit(X, y) + + def predict(self, X): + return self.model.predict(X) + + def evaluate(self, X, y): + y_pred = self.predict(X) + return mean_squared_error(y, y_pred, squared=False) # RMSE diff --git a/pages/Decision_Tree.py b/pages/Decision_Tree.py new file mode 100644 index 0000000..88c38b8 --- /dev/null +++ b/pages/Decision_Tree.py @@ -0,0 +1,65 @@ +import streamlit as st +import numpy as np +import matplotlib.pyplot as plt +from models.decision_tree import DecisionTreeModelClassifier, DecisionTreeModelRegressor +from utils.plot_helpers import plot_confusion_matrix +from utils.data_helpers import get_classification_data, get_regression_data + +st.title("🌳 Decision Tree Simulator") + +mode = st.radio("Choose Mode", ["Classification", "Regression"]) + +if mode == "Classification": + st.subheader("Decision Tree Classifier") + + # Load dataset from utils + X, y = get_classification_data() + + max_depth = st.slider("Max Depth", 1, 10, 3) + criterion = st.selectbox("Criterion", ["gini", "entropy", "log_loss"]) + + model = DecisionTreeModelClassifier(max_depth=max_depth, criterion=criterion) + model.train(X, y) + y_pred = model.predict(X) + + # Decision boundary + x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 + y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 + xx, yy = np.meshgrid(np.linspace(x_min, x_max, 300), + np.linspace(y_min, y_max, 300)) + Z = model.predict(np.c_[xx.ravel(), yy.ravel()]) + Z = Z.reshape(xx.shape) + + plt.figure(figsize=(8, 6)) + plt.contourf(xx, yy, Z, cmap="coolwarm", alpha=0.6) + plt.scatter(X[:, 0], X[:, 1], c=y, cmap="coolwarm", edgecolors="k") + plt.title(f"Decision Boundary (Depth={max_depth}, Criterion={criterion})") + st.pyplot(plt) + + # Confusion matrix + fig = plot_confusion_matrix(y, y_pred, labels=["Class 0", "Class 1"], cmap="Oranges") + st.pyplot(fig) + + st.write(f"**Accuracy:** {model.evaluate(X, y):.2f}") + +else: + st.subheader("Decision Tree Regressor") + + # Load dataset from utils + X, y = get_regression_data() + + max_depth = st.slider("Max Depth", 1, 10, 3) + criterion = st.selectbox("Criterion", ["squared_error", "friedman_mse", "absolute_error", "poisson"]) + + model = DecisionTreeModelRegressor(max_depth=max_depth, criterion=criterion) + model.train(X, y) + y_pred = model.predict(X) + + plt.figure(figsize=(8, 6)) + plt.scatter(X, y, color="blue", label="Data") + plt.plot(X, y_pred, color="red", label="Prediction") + plt.title(f"Decision Tree Regression (Depth={max_depth})") + plt.legend() + st.pyplot(plt) + + st.write(f"**RMSE:** {model.evaluate(X, y):.3f}") diff --git a/utils/data_helpers.py b/utils/data_helpers.py index 80c10f4..c6d3464 100644 --- a/utils/data_helpers.py +++ b/utils/data_helpers.py @@ -1,30 +1,14 @@ -# utils/data_helpers.py +from sklearn.datasets import make_classification, make_regression +import numpy as np -from sklearn.datasets import make_regression -import pandas as pd - -def generate_sample_regression(n_samples=100, n_features=1, noise=0.0, random_state=None): - """ - Generate a sample regression dataset. - - Parameters: - n_samples (int): Number of data points. - n_features (int): Number of features. - noise (float): Standard deviation of Gaussian noise added to the output. - random_state (int or None): Random seed for reproducibility. - - Returns: - X (pd.DataFrame): Feature dataframe of shape (n_samples, n_features) - y (pd.Series): Target variable of shape (n_samples,) - """ - X, y = make_regression( - n_samples=n_samples, - n_features=n_features, - noise=noise, - random_state=random_state +def get_classification_data(): + X, y = make_classification( + n_samples=150, n_features=2, n_informative=2, n_redundant=0, + n_clusters_per_class=1, random_state=42 ) - # Convert to pandas for convenience - X_df = pd.DataFrame(X, columns=[f'feature_{i+1}' for i in range(n_features)]) - y_series = pd.Series(y, name='target') - - return X_df, y_series + return X, y + +def get_regression_data(): + X = np.linspace(0, 10, 100).reshape(-1, 1) + y = np.sin(X).ravel() + np.random.randn(100) * 0.1 + return X, y