层次聚类像一位耐心的考古学家,通过逐层挖掘数据间的亲缘关系,构建出从微观到宏观的多层次数据族谱,既能俯瞰全局结构,又能细察局部关联。
双模式选择:
距离度量艺术:
// 常用距离计算示例
double singleLinkage(double[] a, double[] b) {
double min = Double.MAX_VALUE;
for (int i : a) for (int j : b)
min = Math.min(min, euclideanDistance(i, j));
return min;
}
动态聚类数:通过切割树状图获得任意粒度的聚类结果
import java.util.*;
class Cluster {
int id;
List<Double[]> points = new ArrayList<>();
public Cluster(Double[] point) {
points.add(point);
}
}
public class HierarchicalClustering {
public static void main(String[] args) {
// 样本数据初始化
List<Cluster> clusters = new ArrayList<>();
clusters.add(new Cluster(new Double[]{1.0, 2.0}));
clusters.add(new Cluster(new Double[]{5.0, 6.0}));
clusters.add(new Cluster(new Double[]{1.5, 2.5}));
// 凝聚式聚类过程
while (clusters.size() > 1) {
double minDist = Double.MAX_VALUE;
int[] mergePair = new int[2];
// 查找最近簇对
for (int i=0; i<clusters.size(); i++) {
for (int j=i+1; j<clusters.size(); j++) {
double dist = singleLinkage(clusters.get(i), clusters.get(j));
if (dist < minDist) {
minDist = dist;
mergePair = new int[]{i, j};
}
}
}
// 合并簇
Cluster merged = new Cluster();
merged.points.addAll(clusters.get(mergePair[0]).points);
merged.points.addAll(clusters.get(mergePair[1]).points);
clusters.remove(mergePair[1]);
clusters.remove(mergePair[0]);
clusters.add(merged);
System.out.println("合并后簇数: " + clusters.size());
}
}
// 单链接距离计算
static double singleLinkage(Cluster a, Cluster b) {
double min = Double.MAX_VALUE;
for (Double[] p1 : a.points)
for (Double[] p2 : b.points)
min = Math.min(min, euclidean(p1, p2));
return min;
}
static double euclidean(Double[] a, Double[] b) {
return Math.sqrt(Math.pow(a[0]-b[0],2) + Math.pow(a[1]-b[1],2));
}
}
维度 | 基本实现 | 优化方案 |
---|---|---|
时间复杂度 | O(n³) | O(n² log n) |
空间复杂度 | O(n²) | O(n) |
n=数据点数,优化方案需使用优先队列等数据结构
新手成长阶梯:
dendrogram
解读聚类层次
高手突破方向:
// 内存优化:稀疏矩阵存储
Map<String, Double> distanceCache = new HashMap<>();
// 计算加速:并行化距离计算
clusters.parallelStream().forEach(cluster -> {
// 并行处理逻辑
});
最佳实践提示:当数据量>1万时,建议先使用K-means粗聚类再进行层次分析,像先用望远镜观测再用显微镜研究!