每天进步一点点《ML - 基于层次的聚类》

一些前提的约定,还是沿用上篇文章的哈。先来致敬下男神。
在这里插入图片描述

一:层次聚类(Hierarchical Clustering)介绍
它也是聚类算法的一种,也是我学习的第三种聚类算法,通过计算样本点之间的相似性,也可以理解成距离,构建出一个嵌套层次聚类树,有两种方式,一个是自下而上的合并法,一个是自上而下的分裂法,本文讲解更容易理解的合并法。
在这里插入图片描述

如上图所示,不断地将样本汇聚成小的簇,再将晓得簇不断重复该过程汇聚成更大簇。

二:算法介绍
简单的说层次聚类的合并算法是通过计算每一个类别的数据点与所有数据点之间的距离来确定它们之间的相似性,距离越小,相似度越高。并将距离最近的两个数据点或类别进行组合,生成聚类树。然后不断迭代这一过程,直到最后所有的样本都在一个类别内。

算法详细过程如下:
1:距离矩阵
现在我们需要描述类别和类别之间的相似性,也可以用距离来衡量,我们这里还是用欧氏距离来计算。给定两个样本点x(i), x(j)。
在这里插入图片描述
首先呢,我们需要建立一个距离矩阵D,D(i, j)表示类别i到类别j的距离,D(j, i)表示类别j到类别i的距离,很明显D(i, j)= D(j, i)。D(i, i)就是自身类别到自身的距离,也就是对角线的元素,恒等于0,即D(i, i)=0。
请注意这里的用词,类别,类别可以包含一个样本点,也可以包含多个样本点。
最开始的矩阵,每个类别就是每一个样本点自身,这个矩阵其实也就是样本点到样本点的距离矩阵。
在这里插入图片描述
然后找到距离最小的两个类别,将其合并为一个类别。假设合并了第i个和第j个类别组成一个新的类别{i,j}。那么我们将重新计算距离矩阵,此时{i,j}将作为一个整体参与距离运算,所以之类先必须学习一下,包含有多个样本的类别之间距离计算方法。有三种。
Single Linkage:将两个组合数据点中距离最近的两个数据点间的距离作为这两个组合数据点的距离。这种方法容易受到极端值的影响。
Complete Linkage:的计算方法与Single Linkage相反,将两个组合数据点中距离最远的两个数据点间的距离作为这两个组合数据点的距离。
Average Linkage:计算两个组合数据点中的每个数据点与其他所有数据点的距离。将所有距离的均值作为两个组合数据点间的距离。这种方法计算量比较大,但结果比前两种方法更合理。
Center Linkage:计算两个类别的质心μi和μj之间的距离,我不知道这样做科学不?这个是我临时想到的一种计算的方法。

我们这里使用第三种方法,举个例子。假如有两个类别A和B,A包含有样本{1,2},B包含有样本{3,4}。那么可得:D(A,B)=[D(1,3)+ D(1,4) + D(2,3) + D(2,4)]/4;

三:简单实践一波
在这里插入图片描述

给定这个样本集合,我们希望最后化成2个簇,当然了,我们可以在任意簇群的时候停止迭代即可。我这里实验的话,我想最后聚类成2个簇群。

clear all
clc

% randomly construct the samples
x_1 = [0.5:0.05:1.5];
y_1 = 1.5 .+ rand(1, size(x_1)(2));
x_2 = [2.5:0.05:3.5];
y_2 = 4.5 .+ rand(1, size(x_2)(2));


x = [x_1, x_2];
y = [y_1, y_2];
trainData = [x', y'];

figure();
subplot(1, 2, 1);
hold on;

% drow all the points
scatter(trainData(:, 1), trainData(:, 2), 'g', 'linewidth', 3);

xlim([0,5]);
ylim([0,6]);
%axis equal;
grid on;
xlabel('x1');
ylabel('x2');



% let's start
% calclate all the distance from each point to another point.
m = size(trainData)(1);
D = zeros(m, m);
for i=1:m
	D(:,i) = sqrt(((trainData(i, :) .- trainData) .^ 2) * ones(2,1));
end;

function dis = calDis(Data, arr1 ,arr2)
	dis = 0;
	for i=1:size(arr1)(1)
		for j=1:size(arr2)(1)
			dis += Data(arr1(i), arr2(j));
		end;
	end;
	
	dis = dis /(size(arr1)(1) * size(arr2)(1));
end;

% init the type array
Temp_Type = cell(m , 1);
for i=1:size(Temp_Type)(1)
	Temp_Type{
    
    i,1} = [i];
end;


% the lowest layer of cluster tree should is normal smaple points
prevItr = floor(m/2)-1;

% we set the stop condition is all the samples divided into K clusters
K = 2;

% think that, finally we want all the samples into two clusters.
while size(Temp_Type)(1) > K

	% claculate all distance again
	newSize = size(Temp_Type)(1);
	Temp_Data = cell(newSize , 1);
	for i=1:newSize
		Temp_Data{
    
    i, 1} = [];
		for j=1:newSize
			if i == j
				Temp_Data{
    
    i, 1}(1, end + 1) = [0];
			else 
				Temp_Data{
    
    i, 1}(1, end + 1) = calDis(D, Temp_Type{
    
    i, 1}, Temp_Type{
    
    j, 1});
			end;
		end;
	end;
	
	% find the min distance between two types.
	i=0;
	j=0;
	min_dis = intmax('int32');
	

	for row=2:newSize
		thisRow = Temp_Data{
    
    row, :}(1, 1:row-1);
		val = min(thisRow);
		col = find(thisRow == val);
		if min_dis > val
			min_dis = val;
			i = row;
			j = col;
		end;
	end;

	
	% merge this two type.
	Temp_Type{
    
    i,1} = [Temp_Type{
    
    i,1}, Temp_Type{
    
    j,1}];
	Temp_Type(j,:) = [];
	
end;


subplot(1, 2, 2);
hold on;

% drow all the points
scatter(trainData(Temp_Type{
    
    1}(1, :), 1), trainData(Temp_Type{
    
    1}(1, :), 2), 'r', 'linewidth', 3);
scatter(trainData(Temp_Type{
    
    2}(1, :), 1), trainData(Temp_Type{
    
    2}(1, :), 2), 'b', 'linewidth', 3);

xlim([0,5]);
ylim([0,6]);
%axis equal;
grid on;
xlabel('x1');
ylabel('x2');

聚类结果如下:
在这里插入图片描述

再实验一组数据:
在这里插入图片描述

得到结果如下:
在这里插入图片描述

总结一下:这个算法运行还式很慢的。真的是慢,虽然我的算法可以进行优化,但是还是慢。DBSCAN还是很快的。

猜你喜欢

转载自blog.csdn.net/qq_29367075/article/details/108815664