CoolFace
Apppublic

OMG-01/RG-SC_RobustGammaSpectralClustering

sourceHugging Faceupdated 1y agoView on Hugging Face
1likes
app.py207 linesDownload Raw Back to root
1import gradio as gr2import pandas as pd3import numpy as np4import matplotlib.pyplot as plt5import matplotlib.cm as cm6from sklearn.preprocessing import StandardScaler7from sklearn.decomposition import PCA8from mpl_toolkits.mplot3d import Axes3D9 10# 別ファイルからRG-SCアルゴリズムのコアロジックをインポート11from rg_sc import run_rgsc12 13def process_and_cluster(file_obj, k_nn, max_k):14    """15    アップロードされたCSVファイルを処理し、クラスタリングを実行し、16    結果のファイルと、データの次元数に応じた最適なプロットを返すGradioのメイン関数。17    """18    if file_obj is None:19        raise gr.Error("No file uploaded. Please upload a CSV file.")20 21    try:22        # アップロードされたファイルをDataFrameとして読み込む23        df = pd.read_csv(file_obj.name)24    except Exception as e:25        raise gr.Error(f"Failed to read the file: {e}")26 27    # ---- カラム名の問題を解決するロジック ----28    # DataFrameから数値型のカラムのみを自動で選択する。29    df_numeric = df.select_dtypes(include=np.number)30    31    if df_numeric.empty:32        raise gr.Error("No numerical columns found in the CSV file. Please provide a file with at least two numerical columns.")33    if df_numeric.shape[1] < 2:34        raise gr.Error("Clustering visualization requires at least 2 numerical columns.")35 36    print(f"Found {df_numeric.shape[1]} numerical columns for clustering: {list(df_numeric.columns)}")37 38    # データをNumpy配列に変換し、標準化39    X = df_numeric.values40    X_scaled = StandardScaler().fit_transform(X)41 42    # RG-SCアルゴリズムを実行43    labels, _, estimated_k = run_rgsc(X_scaled, int(k_nn), int(max_k))44    45    # ---- 結果のファイルを作成 ----46    df_result = df.copy()47    df_result['cluster_label'] = labels48    result_csv_path = "/tmp/clustered_result.csv"49    df_result.to_csv(result_csv_path, index=False)50    51    # ---- 結果のプロットを作成 (次元数に応じて分岐) ----52    n_features = X.shape[1]53    fig = plt.figure(figsize=(9, 9))54 55    # --- カラーマップとラベルの設定 ---56    unique_labels = sorted(list(set(labels)))57    n_clusters = len(unique_labels)58    colors = cm.get_cmap('nipy_spectral', n_clusters) if n_clusters > 1 else cm.get_cmap('gray')59 60    # --- プロットロジック ---61    if n_features == 2:62        # ** 2次元の場合: 2D散布図 **63        ax = fig.add_subplot(111)64        for k_idx, k in enumerate(unique_labels):65            mask = (labels == k)66            color_val = k_idx / (n_clusters - 1 if n_clusters > 1 else 1)67            ax.scatter(X[mask, 0], X[mask, 1], 68                       color=colors(color_val),69                       label=f'Cluster {k}', s=50, alpha=0.8, edgecolors='k')70        ax.set_xlabel(df_numeric.columns[0])71        ax.set_ylabel(df_numeric.columns[1])72        ax.set_title(f"2D Clustering Result (k={estimated_k})", fontsize=16)73 74    elif n_features == 3:75        # ** 3次元の場合: 3D散布図 **76        ax = fig.add_subplot(111, projection='3d')77        for k_idx, k in enumerate(unique_labels):78            mask = (labels == k)79            color_val = k_idx / (n_clusters - 1 if n_clusters > 1 else 1)80            ax.scatter(X[mask, 0], X[mask, 1], X[mask, 2],81                       color=colors(color_val),82                       label=f'Cluster {k}', s=50, alpha=0.8, edgecolors='k')83        ax.set_xlabel(df_numeric.columns[0])84        ax.set_ylabel(df_numeric.columns[1])85        ax.set_zlabel(df_numeric.columns[2])86        ax.set_title(f"3D Clustering Result (k={estimated_k})", fontsize=16)87        ax.view_init(elev=20., azim=45) # 見やすい角度に調整88 89    else: # n_features > 390        # ** 4次元以上の場合: PCAによる次元削減プロット **91        ax = fig.add_subplot(111)92        # PCAで2次元に削減93        pca = PCA(n_components=2)94        X_pca = pca.fit_transform(X_scaled)95        96        for k_idx, k in enumerate(unique_labels):97            mask = (labels == k)98            color_val = k_idx / (n_clusters - 1 if n_clusters > 1 else 1)99            ax.scatter(X_pca[mask, 0], X_pca[mask, 1],100                       color=colors(color_val),101                       label=f'Cluster {k}', s=50, alpha=0.8, edgecolors='k')102        103        explained_variance = pca.explained_variance_ratio_.sum() * 100104        ax.set_xlabel("Principal Component 1")105        ax.set_ylabel("Principal Component 2")106        title = (f"PCA Visualization of {n_features}D Data (k={estimated_k})\n"107                 f"Explained Variance: {explained_variance:.2f}%")108        ax.set_title(title, fontsize=14)109 110    ax.grid(True)111    if n_clusters > 0:112        ax.legend()113    114    plot_path = "/tmp/clustering_plot.png"115    plt.savefig(plot_path)116    plt.close(fig)117 118    return result_csv_path, plot_path119 120 121# ---- Gradioインターフェースの構築 ----122with gr.Blocks(theme=gr.themes.Soft()) as demo:123    gr.Markdown("# RG-SC: Self-Tuning Robust Spectral Clustering")124 125    # Tabインターフェースを作成126    with gr.Tabs():127        # --- メインのクラスタリング用タブ ---128        with gr.TabItem("Clustering Tool"):129            gr.Markdown(130                "Upload a CSV file. The RG-SC algorithm will automatically detect all **numerical columns** "131                "to perform clustering, estimate the optimal number of clusters, and group the data."132            )133            with gr.Row():134                with gr.Column(scale=1):135                    file_input = gr.File(label="Upload CSV File")136                    137                    with gr.Accordion("Advanced Settings (Optional)", open=False):138                        k_nn_slider = gr.Slider(5, 30, value=10, step=1, label="k-NN", 139                                                info="Number of neighbors for graph construction. Larger values consider more global structure.")140                        max_k_slider = gr.Slider(5, 15, value=10, step=1, label="Max Clusters", 141                                                 info="The maximum number of clusters to search for.")142                    143                    submit_button = gr.Button("Run Clustering", variant="primary")144 145                with gr.Column(scale=2):146                    gr.Markdown("### Results")147                    plot_output = gr.Image(label="Clustering Result Plot")148                    file_output = gr.File(label="Download Labeled Data")149 150            submit_button.click(151                fn=process_and_cluster,152                inputs=[file_input, k_nn_slider, max_k_slider],153                outputs=[file_output, plot_output]154            )155 156            # サンプルファイルをリポジトリに含めることが前提157            gr.Examples(158                examples=[159                    "easy_unlabeled.csv",160                    "medium_unlabeled.csv",161                    "hard_unlabeled.csv"162                ],163                inputs=[file_input],164                label="Example Datasets (if uploaded to the Space)"165            )166 167        # --- アルゴリズム解説用のタブ ---168        with gr.TabItem("Algorithm Explanation"):169            gr.Markdown("""170            ## The RG-SC Algorithm: A Deep Dive171 172            **RG-SC (Robust, Gamma, Spectral Clustering)** is a sophisticated unsupervised learning algorithm designed to uncover hidden structures in data, even in complex scenarios where traditional methods fail.173 174            ### Core Philosophy: "Connectivity over Proximity"175 176            Unlike K-Means, which relies on distance to a center point, RG-SC is based on **Spectral Clustering**. It transforms the data into a **graph (network)**, where data points are nodes and the connections (edges) between them represent their "similarity" or "connectivity". This allows it to identify clusters of any shape, such as crescents or concentric circles.177 178            ---179 180            ### The 5 Key Steps181 182            #### **Step 1: Intelligent Graph Construction**183            - We build a **Mutual k-NN Graph**. An edge is created between point A and B only if both points consider each other a "close friend". This robust method filters out noise and weak connections, revealing the true skeleton of the data structure.184            - It also features a **Self-Tuning Gamma**, which automatically adjusts the sensitivity of similarity calculations based on the data's density. This ensures high performance across different datasets without manual tuning.185 186            #### **Step 2: Mathematical Representation (Graph Laplacian)**187            - The graph's structure is converted into a special matrix called the **Normalized Graph Laplacian (`L`)**. This matrix mathematically encodes all the connectivity information of the graph.188 189            #### **Step 3: Optimal k-Estimation via Eigen-analysis**190            - We analyze the spectrum of the Laplacian matrix by performing **eigendecomposition**. The **eigenvalues** represent its "cleavability".191            - The algorithm automatically finds the most natural number of clusters, `k`, by detecting the largest **eigengap**—a sharp jump in the sequence of sorted eigenvalues. This indicates the most stable point to partition the graph.192 193            #### **Step 4: Transformation to a Simpler Space (Feature Space)**194            - The `k` eigenvectors corresponding to the smallest eigenvalues are used as a new set of coordinate axes.195            - The original data is projected into this new **feature space**. In this space, complex, intertwined clusters from the original space become simple, well-separated groups.196 197            #### **Step 5: Final Classification**198            - Now that the problem has been drastically simplified, a fast and simple algorithm like **K-Means** is applied to the transformed data in the feature space to assign the final cluster labels.199 200            ---201 202            This multi-step process makes RG-SC a powerful and versatile tool, capable of handling complex shapes, non-uniform densities, and automatically determining the optimal number of clusters.203            """)204 205# Gradioアプリケーションを起動するための定型句206if __name__ == "__main__":207    demo.launch()