diff --git a/frontend/pages/clustering.py b/frontend/pages/clustering.py index b3bf971..2c2fb8e 100644 --- a/frontend/pages/clustering.py +++ b/frontend/pages/clustering.py @@ -1,15 +1,19 @@ import streamlit as st import matplotlib.pyplot as plt from clusters import DBSCANCluster, KMeansCluster, CLUSTERING_STRATEGIES +from sklearn.decomposition import PCA +from sklearn.metrics import silhouette_score +import numpy as np st.header("Clustering") if "data" in st.session_state: data = st.session_state.data - general_row = st.columns([1, 1]) + general_row = st.columns([1, 1, 1]) clustering = general_row[0].selectbox("Clustering method", CLUSTERING_STRATEGIES) - data_name = general_row[1].multiselect("Data Name",data.select_dtypes(include="number").columns, max_selections=3) + data_name = general_row[1].multiselect("Columns", data.select_dtypes(include="number").columns) + n_components = general_row[2].number_input("Reduce dimensions to (PCA)", min_value=1, max_value=3, value=2) with st.form("cluster_form"): if isinstance(clustering, KMeansCluster): @@ -18,20 +22,50 @@ if "data" in st.session_state: clustering.n_init = row1[1].number_input("n_init", min_value=1, value=clustering.n_init) clustering.max_iter = row1[2].number_input("max_iter", min_value=1, value=clustering.max_iter) elif isinstance(clustering, DBSCANCluster): - clustering.eps = st.slider("eps", min_value=0.0001, max_value=1.0, step=0.1, value=clustering.eps) - clustering.min_samples = st.number_input("min_samples", min_value=1, value=clustering.min_samples) + row1 = st.columns([1, 1]) + clustering.eps = row1[0].slider("eps", min_value=0.0001, max_value=1.0, step=0.05, value=clustering.eps) + clustering.min_samples = row1[1].number_input("min_samples", min_value=1, value=clustering.min_samples) st.form_submit_button("Launch") - if len(data_name) >= 2 and len(data_name) <=3: + if len(data_name) > 0: x = data[data_name].to_numpy() + n_components = min(n_components, len(data_name)) + if len(data_name) > n_components: + pca = PCA(n_components) + x = pca.fit_transform(x) + if n_components == 2: + (fig, ax) = plt.subplots(figsize=(8, 8)) + for i in range(0, pca.components_.shape[1]): + ax.arrow( + 0, + 0, + pca.components_[0, i], + pca.components_[1, i], + head_width=0.1, + head_length=0.1 + ) - result = clustering.run(x) + plt.text( + pca.components_[0, i] + 0.05, + pca.components_[1, i] + 0.05, + data_name[i] + ) + circle = plt.Circle((0, 0), radius=1, edgecolor='b', facecolor='None') + ax.add_patch(circle) + plt.axis("equal") + ax.set_title("PCA result - Correlation circle") + st.pyplot(fig) + result = clustering.run(x) + st.write("## Cluster stats") st.table(result.statistics) + st.write("## Graphical representation") fig = plt.figure() - if len(data_name) == 2: + if n_components == 1: + plt.scatter(x, np.zeros_like(x)) + elif n_components == 2: ax = fig.add_subplot(projection='rectilinear') plt.scatter(x[:, 0], x[:, 1], c=result.labels, s=50, cmap="viridis") if result.centers is not None: @@ -43,6 +77,10 @@ if "data" in st.session_state: if result.centers is not None: ax.scatter(result.centers[:, 0], result.centers[:, 1], result.centers[:, 2], c="black", s=200, marker="X") st.pyplot(fig) + if not (result.labels == 0).all(): + st.write("Silhouette score:", silhouette_score(x, result.labels)) + else: + st.error("Select at least one column") else: st.error("file not loaded")