本文介紹了如何使用K-Means算法對相似度較高的語句進行分類,并附上java案例代碼
import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class KMeansTextClustering {public static void main(String[] args) {// 初始化語句數據集List<String> texts = new ArrayList<>();texts.add("如果他不是老師,他就是學生");texts.add("他可能是老師也可能是學生");texts.add("他經常在學校學習");texts.add("他在學校的學習成績很好");texts.add("老師和學生在上課");texts.add("學校是學習的地方");texts.add("老師收到定金");texts.add("學校塑料袋管理科");texts.add("開心數量肯定兩個都是");texts.add("開心的兩個孩子");// 設置K值(簇的數量)int K = 3;// 執行K-Means算法List<List<String>> clusters = kMeans(texts, K);// 打印聚類結果for (int i = 0; i < clusters.size(); i++) {System.out.println("Cluster " + (i + 1) + ":");for (String text : clusters.get(i)) {System.out.println(text);}System.out.println();}}public static List<List<String>> kMeans(List<String> texts, int K) {// 隨機選擇K個語句作為初始簇中心Random random = new Random();List<String> centroids = new ArrayList<>();for (int i = 0; i < K; i++) {centroids.add(texts.get(random.nextInt(texts.size())));}boolean isChanged;List<List<String>> clusters = new ArrayList<>();do {// 創建K個空簇clusters.clear();for (int i = 0; i < K; i++) {clusters.add(new ArrayList<>());}// 分配數據點到最近的簇中心for (String text : texts) {int closestCentroidIndex = 0;double minDistance = Double.MAX_VALUE;for (int i = 0; i < K; i++) {double similarity = 1 - calcTextSim(text, centroids.get(i)); // 使用相似度的補數作為距離if (similarity < minDistance) {minDistance = similarity;closestCentroidIndex = i;}}clusters.get(closestCentroidIndex).add(text);}// 更新簇中心isChanged = false;for (int i = 0; i < K; i++) {String newCentroid = findCentroid(clusters.get(i), centroids.get(i));if (!newCentroid.equals(centroids.get(i))) {isChanged = true;centroids.set(i, newCentroid);}}} while (isChanged);return clusters;}// 計算兩個語句的相似度public static double calcTextSim(String text, String targetText) {return ChineseTextRecommender.calcTextSim(text, targetText); // 返回相似度值}// 計算簇的中心點(這里簡化為返回簇中第一個元素)public static String findCentroid(List<String> cluster, String currentCentroid) {if (cluster.isEmpty()) return currentCentroid;// 存儲每個語句的平均相似度double[] averageSimilarities = new double[cluster.size()];// 計算每個語句與其他語句的平均相似度for (int i = 0; i < cluster.size(); i++) {double totalSimilarity = 0.0;for (int j = 0; j < cluster.size(); j++) {if (i != j) {totalSimilarity += calcTextSim(cluster.get(i), cluster.get(j));}}averageSimilarities[i] = totalSimilarity / (cluster.size() - 1);}// 找到平均相似度最高的語句作為簇中心點int centroidIndex = 0;double maxAverageSimilarity = averageSimilarities[0];for (int i = 1; i < averageSimilarities.length; i++) {if (averageSimilarities[i] > maxAverageSimilarity) {maxAverageSimilarity = averageSimilarities[i];centroidIndex = i;}}return cluster.get(centroidIndex);}
}
相似度工具:
import com.hankcs.hanlp.tokenizer.StandardTokenizer;import java.util.*;
import java.util.stream.Collectors;public class ChineseTextRecommender {public static double calcTextSim(String text, String targetText) {Map<String, Integer> targetVector = buildTermVector(targetText);Map<String, Integer> textVector = buildTermVector(text);double similarity = cosineSimilarity(targetVector, textVector);return similarity;}public static Map<String, Integer> buildTermVector(String text) {List<String> words = StandardTokenizer.segment(text).stream().map(term -> term.word).collect(Collectors.toList());Map<String, Integer> termVector = new HashMap<>();for (String word : words) {termVector.put(word, termVector.getOrDefault(word, 0) + 1);}return termVector;}// 計算余弦相似度public static double cosineSimilarity(Map<String, Integer> vectorA, Map<String, Integer> vectorB) {double dotProduct = 0.0;double normA = 0.0;double normB = 0.0;for (String key : vectorA.keySet()) {dotProduct += vectorA.get(key) * (vectorB.getOrDefault(key, 0));normA += Math.pow(vectorA.get(key), 2);}for (String key : vectorB.keySet()) {normB += Math.pow(vectorB.get(key), 2);}if (normA == 0 || normB == 0) {return 0.0;}return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));}
}
pom依賴
<!-- 分詞工具 --><dependency><groupId>com.hankcs</groupId><artifactId>hanlp</artifactId><version>portable-1.8.4</version></dependency>
打印結果:
Cluster 1:
他經常在學校學習
他在學校的學習成績很好
學校是學習的地方
學校塑料袋管理科Cluster 2:
開心數量肯定兩個都是
開心的兩個孩子Cluster 3:
如果他不是老師,他就是學生
他可能是老師也可能是學生
老師和學生在上課
老師收到定金