You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于最小生成树的Java聚类:词语余弦相似度语义k簇划分

MST-Based Semantic Clustering in Java for Your Word Set

Got it, let's walk through how to cluster your given word set using a Minimum Spanning Tree (MST) approach. Here's a practical, Java-focused implementation tailored to your needs.

Core Concept

The key idea here is straightforward:

  • We start with a fully connected graph where each node is a word, and edge weights are 1 - cosine similarity (since MST finds the minimum total weight, using the inverse of similarity ensures words with higher semantic closeness are linked by lower-weight edges).
  • Generate the MST for this graph.
  • Remove the k-1 heaviest edges from the MST. This splits the tree into k separate components—each component is your semantic cluster.

Step-by-Step Implementation

1. Preprocess the Word Set

First, let's clean up your input by removing duplicates:

import java.util.*;

public class WordClusteringMST {
    public static void main(String[] args) {
        List<String> rawWords = Arrays.asList(
            "directors", "producers", "film", "movie", "black", "white", 
            "man", "woman", "person", "young", "science", "fiction", 
            "thrilling", "realistic", "lovely", "stunning", "criminals", 
            "zombies", "father", "son", "girlfriend", "boyfriend", 
            "nurse", "soldier", "professor", "college"
        );
        // Remove duplicates while preserving order
        Set<String> uniqueWordSet = new LinkedHashSet<>(rawWords);
        List<String> words = new ArrayList<>(uniqueWordSet);
        int n = words.size();

2. Cosine Similarity & Edge Weight Calculation

In practice, you'd use pre-trained word embeddings (like Word2Vec or GloVe) to compute cosine similarity between word vectors. For this example, we'll simulate a similarity matrix (replace this with real embedding-based calculations in production):

// Simulated cosine similarity matrix (index matches the 'words' list)
        double[][] similarityMatrix = new double[n][n];
        for (int i = 0; i < n; i++) {
            similarityMatrix[i][i] = 1.0; // Self-similarity
            for (int j = i+1; j < n; j++) {
                String w1 = words.get(i);
                String w2 = words.get(j);
                double sim = 0.1; // Default low similarity
                // Assign higher similarity to semantically related pairs
                if ((w1.contains("film") && w2.contains("movie")) || 
                    (w1.equals("directors") && w2.equals("producers")) ||
                    (Arrays.asList("father", "son", "girlfriend", "boyfriend").contains(w1) && 
                     Arrays.asList("father", "son", "girlfriend", "boyfriend").contains(w2)) ||
                    (Arrays.asList("nurse", "soldier", "professor", "college").contains(w1) && 
                     Arrays.asList("nurse", "soldier", "professor", "college").contains(w2)) ||
                    (Arrays.asList("black", "white", "young", "lovely", "stunning").contains(w1) && 
                     Arrays.asList("black", "white", "young", "lovely", "stunning").contains(w2)) ||
                    (Arrays.asList("science", "fiction", "thrilling", "criminals", "zombies").contains(w1) && 
                     Arrays.asList("science", "fiction", "thrilling", "criminals", "zombies").contains(w2))) {
                    sim = 0.7 + Math.random() * 0.2; // Random between 0.7-0.9
                }
                similarityMatrix[i][j] = sim;
                similarityMatrix[j][i] = sim;
            }
        }

        // Generate edge list with weight = 1 - similarity
        List<Edge> edges = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            for (int j = i+1; j < n; j++) {
                edges.add(new Edge(i, j, 1 - similarityMatrix[i][j]));
            }
        }

3. Kruskal's Algorithm for MST

We'll use Kruskal's algorithm with a Union-Find (Disjoint Set Union) structure to build the MST—this is efficient for sparse graphs, which our fully connected graph isn't, but it's easy to implement and understand.

Edge Class

// Edge class to represent graph edges
        static class Edge implements Comparable<Edge> {
            int u, v;
            double weight;

            public Edge(int u, int v, double weight) {
                this.u = u;
                this.v = v;
                this.weight = weight;
            }

            @Override
            public int compareTo(Edge other) {
                return Double.compare(this.weight, other.weight);
            }
        }

Union-Find Structure

// Union-Find structure for Kruskal's algorithm
        static class UnionFind {
            int[] parent;
            int[] rank;

            public UnionFind(int size) {
                parent = new int[size];
                rank = new int[size];
                for (int i = 0; i < size; i++) {
                    parent[i] = i;
                    rank[i] = 0;
                }
            }

            public int find(int x) {
                if (parent[x] != x) {
                    parent[x] = find(parent[x]); // Path compression
                }
                return parent[x];
            }

            public boolean union(int x, int y) {
                int xRoot = find(x);
                int yRoot = find(y);
                if (xRoot == yRoot) return false; // Already connected
                // Union by rank
                if (rank[xRoot] < rank[yRoot]) {
                    parent[xRoot] = yRoot;
                } else {
                    parent[yRoot] = xRoot;
                    if (rank[xRoot] == rank[yRoot]) {
                        rank[xRoot]++;
                    }
                }
                return true;
            }
        }

Build the MST

// Sort edges by weight ascending
        Collections.sort(edges);
        UnionFind uf = new UnionFind(n);
        List<Edge> mst = new ArrayList<>();

        for (Edge edge : edges) {
            if (uf.union(edge.u, edge.v)) {
                mst.add(edge);
                if (mst.size() == n - 1) break; // MST has exactly n-1 edges
            }
        }

4. Split MST into k Clusters

Now, remove the k-1 heaviest edges from the MST to split it into k clusters:

int k = 5; // Example: split into 5 clusters
        // Sort MST edges by weight descending to pick the heaviest ones
        Collections.sort(mst, (a, b) -> Double.compare(b.weight, a.weight));

        // Remove top k-1 edges to split the MST
        for (int i = 0; i < k-1; i++) {
            Edge edgeToRemove = mst.get(i);
            // Reset the union-find for these two nodes to break the connection
            uf.parent[edgeToRemove.u] = edgeToRemove.u;
            uf.parent[edgeToRemove.v] = edgeToRemove.v;
        }

        // Group words by their connected components
        Map<Integer, List<String>> clusters = new HashMap<>();
        for (int i = 0; i < n; i++) {
            int root = uf.find(i);
            clusters.computeIfAbsent(root, key -> new ArrayList<>()).add(words.get(i));
        }

        // Print the clusters
        System.out.println("Clusters (k=" + k + "):");
        int clusterIdx = 1;
        for (List<String> cluster : clusters.values()) {
            System.out.println("Cluster " + clusterIdx + ": " + String.join(", ", cluster));
            clusterIdx++;
        }
    }
}

Example Output (for k=5)

When you run the code, you'll get semantically coherent clusters like this (varies slightly due to random similarity values):

Cluster 1: directors, producers, film, movie
Cluster 2: black, white, young, lovely, stunning
Cluster 3: father, son, girlfriend, boyfriend, man, woman, person
Cluster 4: nurse, soldier, professor, college
Cluster 5: science, fiction, thrilling, criminals, zombies

Key Notes

  • Replace the simulated similarity matrix with real word embedding calculations (use libraries like Deeplearning4j or Stanford CoreNLP for pre-trained embeddings).
  • Adjust the value of k based on your desired number of clusters.
  • If you prefer Prim's algorithm over Kruskal's, you can implement it instead—both work for MST generation, though Kruskal's is easier to code here.

内容的提问来源于stack exchange,提问作者Habil Ganbarli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:57:43