m7n's picture
Update app.py
2c551c4 verified
raw
history blame contribute delete
No virus
13.3 kB
# -*- coding: utf-8 -*-
"""01_clustering_methods.ipynb
Automatically generated by Colaboratory.
Original file is located at
https://colab.research.google.com/drive/1mqAGInsaItbKYVUlP9muYz3fpdGBWFz5
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import sklearn.cluster as cluster
import colormaps as cmaps
import opinionated
plt.style.use("opinionated_rc")
from opinionated.core import download_googlefont
download_googlefont('Quicksand', add_to_cache=True)
plt.rc('font', family='Quicksand')
#wget https://github.com/scikit-learn-contrib/hdbscan/raw/master/notebooks/clusterable_data.npy
#!wget https://github.com/mwaskom/seaborn-data/raw/master/penguins.csv
import requests
# URLs of the files to download
clusterable_data_url = "https://github.com/scikit-learn-contrib/hdbscan/raw/master/notebooks/clusterable_data.npy"
penguins_csv_url = "https://github.com/mwaskom/seaborn-data/raw/master/penguins.csv"
# Function to download and save a file from a URL
def download_file(url, local_filename):
with requests.get(url, stream=True) as r:
r.raise_for_status()
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
# Download the files
download_file(clusterable_data_url, "clusterable_data.npy")
download_file(penguins_csv_url, "penguins.csv")
print("Files downloaded successfully.")
hdbscan_example_data = np.load('clusterable_data.npy')
penguins_dataset = pd.read_csv('penguins.csv')[['bill_length_mm','bill_depth_mm','flipper_length_mm']].dropna().values
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
penguins_dataset_standardized = scaler.fit_transform(penguins_dataset)
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs, make_moons, load_iris
import seaborn as sns
import pandas as pd
import matplotlib.colors as mcolors
from sklearn.cluster import KMeans
from sklearn.cluster import AgglomerativeClustering
from sklearn.mixture import GaussianMixture
import hdbscan
import genieclust
# Pre-defined datasets
blobs_X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
moons_X, _ = make_moons(n_samples=300, noise=0.05, random_state=0)
# Penguins dataset (3D example)
# For the purpose of this example, let's simulate the Penguins dataset with iris for simplicity
iris_X, _ = load_iris(return_X_y=True)
# Assuming iris_X to be a placeholder for the Penguins dataset with numerical features
datasets = {
"Blobs": blobs_X,
"Moons": moons_X,
"Penguins": penguins_dataset_standardized, # Placeholder for Penguins dataset
"hDBSCAN sample": hdbscan_example_data
}
# Function for plotting the unclustered dataset
def plot_unclustered(dataset_name):
X = datasets[dataset_name] # Fetch dataset from the dictionary
# Check if the dataset has more than 2 dimensions
if X.shape[1] > 2:
# Convert dataset to DataFrame for seaborn pairplot
df = pd.DataFrame(X)
fig = sns.pairplot(df, plot_kws={'color': 'grey','alpha':0.7}, diag_kws={'color': 'grey'}).fig
else:
fig, ax = plt.subplots(figsize=(8, 6))
ax.scatter(X[:, 0], X[:, 1], color='gray', marker='.',alpha=.7)
ax.set_xlabel("Feature 1")
ax.set_ylabel("Feature 2")
ax.grid(True)
plt.tight_layout()
plt.close(fig)
return fig
def plot_clustered(dataset_name, clustering_method, kmeans_n_clusters, agg_n_clusters, agg_linkage, gmm_n_clusters, covariance_type,
genie_n_clusters, gini_threshold, M,hdbscan_min_cluster_size, hdbscan_min_samples):
X = datasets[dataset_name]
# Determine the clustering method and fit the model accordingly
if clustering_method == "K-Means":
model = KMeans(n_clusters=kmeans_n_clusters)
model.fit(X)
labels = model.labels_ # For K-Means, labels are in .labels_
elif clustering_method == "Agglomerative":
model = AgglomerativeClustering(n_clusters=agg_n_clusters, linkage=agg_linkage)
model.fit(X)
labels = model.labels_ # For Agglomerative Clustering, labels are in .labels_
elif clustering_method == "Gaussian Mixture":
model = GaussianMixture(n_components=gmm_n_clusters, covariance_type=covariance_type)
model.fit(X)
labels = model.predict(X) # For Gaussian Mixture, use .predict() to get labels
elif clustering_method == "Genie":
model = genieclust.Genie(n_clusters=genie_n_clusters, gini_threshold=gini_threshold, M=M)
labels = model.fit_predict(X) # GenieClust uses fit_predict directly for both fitting and label prediction
elif clustering_method == "h-DBSCAN":
clusterer = hdbscan.HDBSCAN(min_cluster_size=hdbscan_min_cluster_size, min_samples=hdbscan_min_samples).fit(X)
labels = clusterer.labels_
n_clusters= len(np.unique([x for x in labels if x >= 0]))
if n_clusters <= 10:
original_cmap = cmaps.greenorange_12
colors = original_cmap([x for x in range(n_clusters)])
# Create a new listed colormap with the extracted colors
new_cmap = mcolors.ListedColormap(colors)
else:
new_cmap = cmaps.cet_g_bw_minc
cluster_colors = [new_cmap(x) if x >= 0
else (0.5, 0.5, 0.5)
for x in labels]
# Check if the dataset has more than 2 dimensions
if X.shape[1] > 2:
# Convert dataset to DataFrame for seaborn pairplot
df = pd.DataFrame(X)
# df['cluster'] = labels
# fig = sns.pairplot(df, color = cluster_colors, cmap=new_cmap).fig
# Create bins for each variable
n_bins = 10
bins = {column: np.linspace(df[column].min(), df[column].max(), n_bins+1) for column in df.columns}
# Create a figure and axes
n = len(df.columns)
fig, axes = plt.subplots(nrows=n, ncols=n, figsize=(n*2.3, n*2.3))
for i in range(n):
for j in range(n):
ax = axes[i, j]
ax.grid(True, which='both', linestyle='--', linewidth=0.5)
if i != j:
ax.scatter(df[df.columns[j]], df[df.columns[i]], c=cluster_colors, alpha=0.8, marker='o',s = 10)
else: # Diagonal - Stacked Bar Charts
data = df[df.columns[i]]
counts = np.zeros((n_bins, n_clusters))
for cluster in range(n_clusters):
cluster_data = data[labels == cluster]
hist, _ = np.histogram(cluster_data, bins=bins[df.columns[i]])
counts[:, cluster] = hist
for cluster in range(n_clusters):
ax.bar(range(n_bins), counts[:, cluster], width=1, align='center',
bottom=np.sum(counts[:, :cluster], axis=1), color=cluster_colors[list(labels).index(cluster)] )
# Explicit axis lines at the bottom and left
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(True)
ax.spines['left'].set_visible(True)
# Hide axis marks for inner plots and adjust label size
if i < n - 1:
ax.tick_params(labelbottom=False) # Hide x-axis labels for all but bottom row
else:
ax.tick_params(axis='x', labelsize=8) # Smaller labels for x-axis
if j > 0:
ax.tick_params(labelleft=False) # Hide y-axis labels for all but first column
else:
ax.tick_params(axis='y', labelsize=8) # Smaller labels for y-axis
# Set labels for outer plots only
if i == n - 1:
ax.set_xlabel(df.columns[j], rotation=0, fontsize=12)
if j == 0:
ax.set_ylabel(df.columns[i], fontsize=12)
else:
fig, ax = plt.subplots(figsize=(8, 6))
ax.scatter(X[:, 0], X[:, 1], c=cluster_colors, marker='.')
ax.grid(True)
plt.tight_layout()
plt.close(fig)
return fig
intro_md = """
# Cluster-algorithm-explorer
_by [Max Noichl](https://homepage.univie.ac.at/maximilian.noichl/), for the clustering & data-visualization-workshop, Bremen, 2024_
Below you can test a number of clustering-algorithms on several easier and harder datasets.
"""
# Gradio interface setup remains the same
with gr.Blocks(theme=gr.themes.Monochrome()) as demo:
with gr.Column():
gr.Markdown(intro_md)
with gr.Row():
with gr.Column():
gr.Markdown("# Choose your dataset:")
dataset_dropdown = gr.Dropdown(label="Select a dataset", choices=list(datasets.keys()), value="Blobs")
gr.Markdown("# Choose your Clustering algorithm & Parameters:")
# Update the dropdown for clustering method to include "Genie"
clustering_method_dropdown = gr.Dropdown(label="Select a clustering method", choices=["K-Means", "Agglomerative", "Gaussian Mixture", "Genie", "h-DBSCAN"], value="K-Means")
# K-Means parameters
with gr.Group(visible=True) as kmeans_params_group:
kmeans_n_clusters_slider = gr.Slider(minimum=2, maximum=10, step=1, label="Number of Clusters (K-Means)", value=4)
# Agglomerative Clustering parameters
with gr.Group(visible=False) as agglomerative_params_group:
agg_n_clusters_slider = gr.Slider(minimum=2, maximum=10, step=1, label="Number of Clusters (Agglomerative)", value=4)
agg_linkage_dropdown = gr.Dropdown(label="Linkage Type", choices=["ward", "complete", "average", "single"], value="ward")
# Gaussian Mixture Model parameters
with gr.Group(visible=False) as gmm_params_group:
gmm_n_clusters_slider = gr.Slider(minimum=2, maximum=10, step=1, label="Number of Components (GMM)", value=4)
covariance_type_dropdown = gr.Dropdown(label="Covariance Type", choices=["full", "tied", "diag", "spherical"], value="full")
# GenieClust parameters
with gr.Group(visible=False) as genie_params_group:
genie_n_clusters_slider = gr.Slider(minimum=2, maximum=10, step=1, label="Number of Clusters (Genie)", value=4)
gini_threshold_slider = gr.Slider(minimum=0.0, maximum=1.05, step=0.05, label="Gini Threshold (Genie)", value=.3)
M_slider = gr.Slider(minimum=0.5, maximum=2.0, step=0.1, label="M Parameter (Genie)", value=1.0)
with gr.Group(visible=False) as hdbscan_params_group:
hdbscan_min_cluster_size = gr.Slider(minimum=2, maximum=200, step=1, label="Minimal Cluster Size (hDBSCAN)", value=10)
hdbscan_min_samples = gr.Slider(minimum=2, maximum=200, step=1, label="Min. Samples (hDBSCAN)", value=10)
# Update the function that changes visible parameter groups based on selected clustering method
def update_method_params(clustering_method):
return {
kmeans_params_group: gr.Group(visible=clustering_method == "K-Means"),
agglomerative_params_group: gr.Group(visible=clustering_method == "Agglomerative"),
gmm_params_group: gr.Group(visible=clustering_method == "Gaussian Mixture"),
genie_params_group: gr.Group(visible=clustering_method == "Genie"),
hdbscan_params_group: gr.Group(visible=clustering_method == "h-DBSCAN"),
}
clustering_method_dropdown.change(update_method_params, inputs=[clustering_method_dropdown], outputs=[kmeans_params_group, agglomerative_params_group,
gmm_params_group, genie_params_group,hdbscan_params_group])
button = gr.Button("Run Clustering!")
with gr.Column():
unclustered_plot_output = gr.Plot(label=None)
clustered_plot_output = gr.Plot(label=None)
dataset_dropdown.change(plot_unclustered, inputs=[dataset_dropdown], outputs=[unclustered_plot_output])
demo.load(plot_unclustered, inputs=[dataset_dropdown], outputs=[unclustered_plot_output])
# Update the button click event to include new parameters for GenieClust
button.click(
plot_clustered,
inputs=[
dataset_dropdown,
clustering_method_dropdown,
kmeans_n_clusters_slider,
agg_n_clusters_slider,
agg_linkage_dropdown,
gmm_n_clusters_slider,
covariance_type_dropdown,
genie_n_clusters_slider, # Add Genie parameters
gini_threshold_slider,
M_slider,
hdbscan_min_cluster_size,
hdbscan_min_samples
],
outputs=[clustered_plot_output]
)
if __name__ == "__main__":
demo.launch(debug=True)