Kmeans的缺点
对K个质心的初始选取比较敏感,如果初始质心选取得不好有可能陷入局部最小值,这个问题可以通过运行多次Kmeans来选取最优结果尽可能避免
二分Kmeans的思路
(1)将数据看成一个簇,对数据进行二分类Kmeans进行初始化
(2)找到最大SSE所在的簇,对该簇进行二分类Kmeans
(3)每次增加一个簇,直到达到所要求的簇数
Matlab代码
function [idx , C , SSE] = binary_kmeans(X , k)
% 二分kmeans算法
% X: 数据矩阵,维度是nxm,有n个数据点,m个特征
% k: 聚类的簇数
% idx: 每个数据点的标签,维度为nx1
% C: 聚类中心,维度为kxm
n = size(X, 1); %计算数据矩阵有多少个数据点
%%%进行一次2分类kmeans初始化聚类中心和标签
[idx,C]= kmeans(X, 2, 'MaxIter', 500 , 'Replicate',100); %使用kmeans对最大sse所在类的数据进行二分类
%初始化C有两个中心
%初始化idx有两种label
while size(C, 1) < k %当簇数小于指定的簇数时,迭代
%将SSE最大的簇使用kmeans进行2分类
sse = zeros(size(C, 1), 1); %初始化sse数组
for i = 1:size(C, 1)
sse(i) = sum(sum((X(idx == i, :) - C(i, :)).^2)); %计算每一类的sse
end
[~, max_idx] = max(sse); %找到最大的sse所在的类
if max_idx ~= 1 %将max_idx的标签换到1
C_1 = C(1,:); %交换最大标签和1标签的中心坐标
C(1,:) = C(max_idx,:);
C(max_idx,:) = C_1;
idx(idx==1) = 0; %交换最大标签和1标签的数据的label
idx(idx==max_idx) = 1;
idx(idx==0) = max_idx;
end
X_temp = X(idx == 1, :); %提取标签为1的数据
[idx_temp,C_temp]= kmeans(X_temp, 2, 'MaxIter', 500 , 'Replicate',100); %使用kmeans对最大sse所在类的数据进行二分类
C(1,:) = C_temp(1,:); %更新C,用二分类第一类中心取代原有的中心
C = [C;C_temp(2,:)]; %在C的最后加上二分类第二类中心
idx(idx == 1) = size(C, 1); %将进行二分的label置为C的行数(此时label中不存在C的行数的)
idx_temp(idx_temp == 1) = 1; %用原来的label取代二分类第一类的label
idx_temp(idx_temp == 2) = size(C,1); %用C的行数取代二分类第二类的label
idx(idx == size(C, 1)) = idx_temp; %将进行二分类的原label用新的两类label替代
end
for i = 1:size(C, 1)
sse(i) = sum(sum((X(idx == i, :) - C(i, :)).^2)); %计算每一类的sse
end
SSE = sum(sse); %计算总的sse
end
通过运行多次二分Kmeans,找到最优的结果
SSE = inf;
idx = zeros(n,1);
for itr = 1:100 %在100次bikmeans中找最优解
[idx_temp,~,SSE_temp] = binary_kmeans(X,k); %使用bikmeans
if SSE_temp < SSE
SSE = SSE_temp;
idx = idx_temp;
end
end