目录
一、实验目的
1、理解C均值(K-means)聚类算法的基本原理;
2、学会用MATLAB实现C均值(K-means)算法;
二、实验原理
(一)相似性度量
1、欧氏距离
欧式距离即欧几里得距离,简称距离,一般情况下我们所用的距离都为欧氏距离。设X1、X2为n维特征空间中的两个模式样本,X1 = (x11, x12, ..., x1n)T, X2 = (x21, x22, ..., x2n)T,则欧氏距离定义为:
欧氏距离可看成是向量(X1-X2)的模值。两点的欧氏距离越小,可认为它们越相似,D(X1, X2)有时记为De(X1, X2),以特指欧几里得距离。
2、马氏距离
马氏距离也称为马哈拉诺比斯距离。设X1 = (x11, x12, ..., x1n)T, X2 = (x21, x22, ..., x2n)T为n维集 中的两个模式向量,N = || 表示 中的向量个数,M = (m1, m2, ..., mn)T = 为均值向量,C为模式集 的协方差矩阵,则马氏距离就定义为:
协方差矩阵C为对称矩阵,对于样本集 ={X1, X2, ..., XN},通常协方差矩阵C的无偏估计计算形式为:
(二)C-均值算法
算法概述如下:
1、初始化。输人N个模式样本X1, X2, ..., XN,置类数K的值(K<=N),置迭代运算的次序号n的初值为1,即n=1。选样本集中的任意K个样本作为初始聚类中心Z1(n), Z2(n), ZK(n)(即Z1(1), Z2(1), ZK(1))。
2、计算每个样本X与每个聚类中心的欧氏距离D(X,ZK(n)),k=1, 2, ..., K,按最小距离原则将样本X分配到离其聚类中心最小的类中,即:
也就是将X归到当前n次聚类的第1类,并自然形成n+1步即下步的各类集合
3、计算新的聚类中心
其中, 为 中所含样本个数。此即分别计算K个聚类中的样本均值向量来作为新的聚类中心。因每次都要计算K个类的样本均值向量,故也称其为K -均值聚类算法。
4、若 , 或有样本发生过类属的变化,则n=n+1, 转至第二步。否则,即 ,或无样本发生过类属变化,则算法收敛,聚类结束。
(三)轮廓系数
轮廓系数是聚类效果好坏的一种评价方式。它用内聚度和分离度评价聚类结果。假设待聚类样本聚成k个类 。每个样本 的轮廓系数ci定义为:
其中,ai表示Xi到其所在同一类内其他样本点不相似程度的平均值:
bi表示Xi到其他类样本点的平均不相似程度的最小值:
ci接近1,说明样本Xi归类合理,接近-1,说明Xi聚类到另外的类中更合理。所有样本点的轮廓系数的平均值即为总轮廓系数c,即:
三、实验内容
1、使用C-均值算法对所给数据集进行聚类分析;
2、探究不同分类数k对聚类性能的影响;
3、使用轮廓系数指标对聚类效果进行评估。
四、实验结果及分析
(一)实验结果
通过使用欧氏距离和马氏距离两种相似度度量标准得到不同的聚类结果如下表1和表2所示,为了便于评估聚类效果,表中也包含了不同类数K下的轮廓系数以及每簇的数据量。
表1-1 欧氏距离下选定不同类数结果 | ||||
类数K | 轮廓系数c | 簇数i | 每簇数据量n | 质心坐标Zi |
K=2 | 0.5922 | 1 | 312 | ( -6.75, 0.74 ) |
2 | 688 | ( 4.14, -7.54 ) | ||
K=3 | 0.6537 | 1 | 300 | ( -6.91, 0.93 ) |
2 | 296 | ( -0.07, -6.84 ) | ||
3 | 404 | ( 7.02, -7.94 ) | ||
K=4 | 0.4689 | 1 | 294 | ( -6.99, 0.99 ) |
2 | 188 | ( -0.39, -5.36 ) | ||
3 | 126 | ( 0.65, -8.97 ) | ||
4 | 392 | ( 7.13, -7.92 ) |
表1-2 马氏距离下选定不同类数结果 | ||||
类数K | 轮廓系数c | 簇数i | 每簇数据量n | 质心坐标Zi |
K=2 | 0.6264 | 1 | 446 | ( 6.57, -7.70 ) |
2 | 554 | ( -3.95, -2.75 ) | ||
K=3 | 0.4680 | 1 | 411 | ( 6.69, -7.46 ) |
2 | 281 | ( -6.48, 1.15 ) | ||
3 | 308 | ( -0.59, -7.18 ) | ||
K=4 | 0.3160 | 1 | 159 | ( -6.20, 2.44 ) |
2 | 161 | ( -6.84, -1.10 ) | ||
3 | 275 | ( 0.44, -7.87 ) | ||
4 | 405 | ( 6.69, -7.41 ) |
(二)实验图像
图1-1 欧式距离下聚类图像
图1-2 马式距离下聚类图像
(三)实验代码
数据集及代码可与文章顶部进行资源下载
1、text01.m
%样本数据
load('data00_cluster_231017.mat')
% load('data01_cluster_231017.mat')
% sample = [1 2; 3 7; 3 2; 2 1; 5 4; 4 7; 6 4; 5 5]; %测试
k=3;
sum = zeros(k, 1); % 统计每簇的数量
[pattern, class] = Kmeans(X, k);
for i=1:k
[sum(i), ~] = size(class{i});
end
res = Silh_Coef(class, X, k) % 轮廓系数
2、算法函数:Kmeans.m
function [pattern, class] = Kmeans( sample, k)
%% ---------------------参数说明------------------------
% 欧式距离聚类分析
% sample 样本数据
% k 聚类数
%% ------------------初始化聚类中心-------------------
meanidx = 1:k;
[N, m] = size(sample);
for j = 1: k
Z(j, :) = sample(meanidx(j), :);
end
%% ------------------计算新的聚类中心------------------
n = 1;
while(true)
class = cell(k, 1);
value = cell(k, 1);
for i=1 : N
for j=1:k
D(j) = dist(sample(i, :), Z(j, :)');
[minu, index] = min(D);
end
class{index} = cat(1, class{index}, i);
value{index} = cat(1, value{index}, sample(i,:));
end
for j=1:k
Z2(j, :) = mean(value{j});
end
if(isequal(Z, Z2)) %当质心不再更新时完成聚类
break;
else
Z= Z2;
n = n+1;
end
end
%% ------------------显示聚类中心---------------------
% for j=1:k
% fprintf('第%d个聚类中心:', j);
% for p = 1:m
% fprintf('%f, %f', Z2(j, p));
% end
% fprintf('\n');
% end
% fprintf('显示Kmeans聚类结果和每个聚类中包含的样本:');
% celldisp(class);
% celldisp(value)
for i=1:N
pattern(i).feature = sample(i,:);
end
%% ------------------聚类结果可视化---------------------
myStyle = {'rx', 'b*', 'g^', 'ms', 'k.'};
hold on
for i=1 : k
fprintf('%f, %f\n', Z2(i, 1), Z2(i, 2)); %显示聚类中心
plot(value{i}(:, 1), value{i}(:, 2), myStyle{i});
plot(Z2(i, 1), Z2(i, 2), myStyle{5}, 'MarkerSize',30);
end
title(['k = ', num2str(k)]);
axis([-15,15,-15,10]);
hold off
%% ------------------分类显示样本数据---------------------
for j=1:k
r = size(class{j}, 1);
for p=1:r
pattern(class{j}(p)).classno = j;
end
end
% fprintf('显示每个样本的特征及其类号:\n')
% for i =1:N
% fprintf('%d-th sample: ', i);
% for j=1:m
% fprintf('%d ', pattern(i).feature(j));
% end
% fprintf('\n its classno: %d\n', pattern(i).classno);
% end
end
3、马氏距离实现:
function [pattern, class] = Kmeans_mahalDis( sample, k)
%% ---------------------参数说明------------------------
% 马氏距离聚类分析(包括质心)
% sample 样本数据
% k 聚类数
%% ------------------初始化聚类中心-------------------
meanidx = 1:k;
[N, m] = size(sample);
M = zeros(1, m);
M_N = zeros(1, m);
C = zeros(m, m);
D = zeros(1, k);
Z = zeros(k, 2);
Z2 = zeros(k, 2);
for j = 1: k
Z(j, :) = sample(meanidx(j), :);
end
for i=1:m
for j=(i-1)*N+1 : i*N
M_N(i) = M_N(i)+sample(j);
end
M_N(i) = M_N(i) / (N+k);
end
%% ------------------计算新的聚类中心------------------
n = 1;
while(true)
class = cell(k, 1);
value = cell(k, 1);
for i=1:m % 计算M矩阵
for j=(i-1)*k+1 : i*k
M(i) = M(i) + Z(j);
end
M(i) = M(i)/(k+N) +M_N(i);
end
for i=1:N % 计算C矩阵
C = C + (sample(i, :)-M)'*(sample(i, :)-M);
end
for i=1:k
C = C + (Z(i, :)-M)'*(Z(i, :)-M);
end
C = C / (N+k-1);
for i=1 : N % 计算距离并分类
for j=1:k
D(j) = sqrt((sample(i, :)-Z(j, :))*inv(C)*(sample(i, :)-Z(j, :))');
end
[minu, index] = min(D);
class{index} = cat(1, class{index}, i);
value{index} = cat(1, value{index}, sample(i,:));
end
for j=1:k
Z2(j, :) = mean(value{j});
end
if(isequal(Z, Z2)) %当质心不再更新时完成聚类
break;
else
Z= Z2;
n = n+1;
end
end
%% ------------------显示聚类中心---------------------
% for j=1:k
% fprintf('第%d个聚类中心:', j);
% for p = 1:m
% fprintf('%f, %f', Z2(j, p));
% end
% fprintf('\n');
% end
% fprintf('显示Kmeans聚类结果和每个聚类中包含的样本:');
% celldisp(class);
% celldisp(value)
for i=1:N
pattern(i).feature = sample(i,:);
end
%% ------------------聚类结果可视化---------------------
myStyle = {'rx', 'b*', 'g^', 'ms', 'k.'};
for i=1 : k
fprintf('%f, %f\n', Z2(i, 1), Z2(i, 2)); %显示聚类中心
plot(value{i}(:, 1), value{i}(:, 2), myStyle{i});
hold on
plot(Z2(i, 1), Z2(i, 2), myStyle{5}, 'MarkerSize',30);
hold on
end
title(['k = ', num2str(k)]);
axis([-15,15,-15,10]);
hold off
%% ------------------分类显示样本数据---------------------
for j=1:k
r = size(class{j}, 1);
for p=1:r
pattern(class{j}(p)).classno = j;
end
end
% fprintf('显示每个样本的特征及其类号:\n')
% for i =1:N
% fprintf('%d-th sample: ', i);
% for j=1:m
% fprintf('%d ', pattern(i).feature(j));
% end
% fprintf('\n its classno: %d\n', pattern(i).classno);
% end
end
4、轮廓系数函数:Silh_Coef.m
function res = Silh_Coef(class, sample, k)
%% 轮廓系数评估
% class 已经过聚类后的数据
% sample 样本数据
% k 簇数
%% 初始化处理
N = zeros(k, 1);
[sum, ~] = size(sample);
a = zeros(sum, 1);
b = zeros(sum, 1);
c = zeros(sum, 1);
temp = zeros(k-1, 1);
res = 0;
for i=1:k
[N(i), ~] = size(class{i});
end
%% 计算ai和bi
num = 1;
for d=1:k
for i=1:N(d)
for j=1:N(d)
a(num) = a(num) + dist(sample(class{d}(i)), sample(class{d}(j)));
end
a(num) = a(num)/(N(d)-1);
count = 1;
for j=1:k
if j==d
continue
else
for m=1:N(j)
temp(count) = temp(count) + dist(sample(class{d}(i)), sample(class{j}(m)));
end
temp(count) = temp(count)/N(j);
end
count = count+1;
end
b(num) = min(temp);
num = num+1;
end
end
%% 计算ci和res
for i=1:sum
c(i) = (b(i) - a(i))/max(b(i), a(i));
res = res+c(i);
end
res = res/sum;
(四)结果分析
1、通过对比马氏距离和欧氏距离的结果可以看到,二者在每簇数据量、质心坐标以及轮廓系数上都有明显差异。欧氏距离数据分类轮廓类似于圆形,而欧氏距离数据分类轮廓类似于椭圆,且沿着直线x+y-10=0方向聚集。
2、使用欧氏距离进行分类,分类数K=3时轮廓系数越大,越接近1,说明该分类数下聚类效果更好;使用马氏距离进行分类,随着分类数K的增大,轮廓系数逐渐降低,且各簇的数量差异逐渐增大,说明K=2时聚类效果更好。
五、思考与提高
1、哪些因素影响C-均值算法的性能?
答:主要有初始质心的选取、相似性测度指标、数据的规模和维度等。
(1)初始类心的选取:初始类心是随机选取的,这可能会影响最聚类结果。初始类心选择不当,可能导致聚类结果陷入局部最优解,或聚类结果不稳定。
(2)模式相似性测度:C-均值算法基于模式相似性进行聚类,因此,如何定义和计算模式相似性测度对算法的性能有很大影响。
(3)数据规模和维度:在处理大规模高维数据时,C-均值算法可能会面临计算效率和内存消耗的问题。
2、C-均值算法中可否用马氏距离代替欧氏距离?若可以,利弊如何?
答:在C-均值算法中,通常使用欧氏距离作为相似性测度。然而,马氏距离也可以用来衡量样本之间的相似性。
(1)使用马氏距离代替欧氏距离的优点有:
a、更好地考虑了不同特征的尺度差异。马氏距离通过将各指标变量转化为无量纲的数值,可以更好地平衡各维度在聚类中的贡献。
b、当数据符合多元正态分布时,马氏距离具有良好的统计性质。
(2)然而,使用马氏距离也可能会带来一些问题:
a、马氏距离的计算涉及到协方差矩阵的计算和逆运算,这会增加算法的计算复杂度。
b、对于非凸或非球形的类心,欧氏距离通常比马氏距离更敏感,因此使用马氏距离可能会影响聚类结果的稳定性。
3、还有哪些具体改进思路,可以扩展算法的适用范围,获得更好的聚类算法?
答:(1)动态调整簇个数:可以通过评估聚类结果的质量来动态调整簇个数,以获得更好的聚类效果。例
(2)考虑数据的预处理:可以考虑对数据进行预处理,如标准化、归一化等,以消除数据间的尺度差异和量纲差异,提高聚类的效果和质量。
(3)与其他算法结合:可以考虑将C-均值算法与其他聚类算法或机器学习算法结合,以获得更好的聚类效果。例如,可以将C-均值算法与K-最近邻算法、决策树算法等结合使用。