本文介绍了如何使用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:
如果他不是老师,他就是学生
他可能是老师也可能是学生
老师和学生在上课
老师收到定金
913

被折叠的 条评论
为什么被折叠?



