机器学习实战ByMatlab(四)二分K-means算法

前面我们在是实现K-means算法的时候,提到了它本身存在的缺陷:

1.可能收敛到局部最小值

2.在大规模数据集上收敛较慢

对于上一篇博文最后说的,当陷入局部最小值的时候,处理方法就是多运行几次K-means算法,然后选择畸变函数J较小的作为最佳聚类结果。这样的说法显然不能让我们接受,我们追求的应该是一次就能给出接近最优的聚类结果。

其实K-means的缺点的根本原因就是:对K个质心的初始选取比较敏感。质心选取得不好很有可能就会陷入局部最小值。

基于以上情况,有人提出了二分K-means算法来解决这种情况,也就是弱化初始质心的选取对最终聚类效果的影响。

二分K-means算法

在介绍二分K-means算法之前我们先说明一个定义:SSE(Sum of Squared Error),也就是误差平方和,它是用来度量聚类效果的一个指标。其实SSE也就是我们在K-means算法中所说的畸变函数:

SSE计算的就是一个cluster中的每个点到质心的平方差,它可以度量聚类的好坏。显然SSE越小,说明聚类效果越好。

二分K-means算法的主要思想:

首先将所有点作为一个簇,然后将该簇一分为二。之后选择能最大程度降低聚类代价函数(也就是误差平方和)的簇划分为两个簇。以此进行下去,直到簇的数目等于用户给定的数目k为止。

二分k均值算法的伪代码如下:

将所有数据点看成一个簇

    当簇数目小于k时

      对每一个簇

          计算总误差

          在给定的簇上面进行k-均值聚类(k=2)

          计算将该簇一分为二后的总误差

      选择使得误差最小的那个簇进行划分操作

Matlab 实现

function bikMeans
%%
clc
clear
close all
%%
biK = 4;
biDataSet = load(‘testSet.txt‘);
[row,col] = size(biDataSet);
% 存储质心矩阵
biCentSet = zeros(biK,col);
% 初始化设定cluster数量为1
numCluster = 1;
%第一列存储每个点被分配的质心,第二列存储点到质心的距离
biClusterAssume = zeros(row,2);
%初始化质心
biCentSet(1,:) = mean(biDataSet)
for i = 1:row
    biClusterAssume(i,1) = numCluster;
    biClusterAssume(i,2) = distEclud(biDataSet(i,:),biCentSet(1,:));
end
while numCluster < biK
    minSSE = 10000;
    %寻找对哪个cluster进行划分最好,也就是寻找SSE最小的那个cluster
    for j = 1:numCluster
        curCluster = biDataSet(find(biClusterAssume(:,1) == j),:);
        [spiltCentSet,spiltClusterAssume] = kMeans(curCluster,2);
        spiltSSE = sum(spiltClusterAssume(:,2));
        noSpiltSSE = sum(biClusterAssume(find(biClusterAssume(:,1)~=j),2));
        curSSE = spiltSSE + noSpiltSSE;
        fprintf(‘第%d个cluster被划分后的误差为:%f \n‘ , [j, curSSE])
        if (curSSE < minSSE)
            minSSE = curSSE;
            bestClusterToSpilt = j;
            bestClusterAssume = spiltClusterAssume;
            bestCentSet = spiltCentSet;
        end
    end
    bestClusterToSpilt
    bestCentSet
     %更新cluster的数目
    numCluster = numCluster + 1;
    bestClusterAssume(find(bestClusterAssume(:,1) == 1),1) = bestClusterToSpilt;
    bestClusterAssume(find(bestClusterAssume(:,1) == 2),1) = numCluster;
    % 更新和添加质心坐标
    biCentSet(bestClusterToSpilt,:) = bestCentSet(1,:);
    biCentSet(numCluster,:) = bestCentSet(2,:);
    biCentSet
    % 更新被划分的cluster的每个点的质心分配以及误差
    biClusterAssume(find(biClusterAssume(:,1) == bestClusterToSpilt),:) = bestClusterAssume;
end

figure
%scatter(dataSet(:,1),dataSet(:,2),5)
for i = 1:biK
    pointCluster = find(biClusterAssume(:,1) == i);
    scatter(biDataSet(pointCluster,1),biDataSet(pointCluster,2),5)
    hold on
end
%hold on
scatter(biCentSet(:,1),biCentSet(:,2),300,‘+‘)
hold off

end

% 计算欧式距离
function dist = distEclud(vecA,vecB)
    dist  = sum(power((vecA-vecB),2));
end

% K-means算法
function [centSet,clusterAssment] = kMeans(dataSet,K)

[row,col] = size(dataSet);
% 存储质心矩阵
centSet = zeros(K,col);
% 随机初始化质心
for i= 1:col
    minV = min(dataSet(:,i));
    rangV = max(dataSet(:,i)) - minV;
    centSet(:,i) = repmat(minV,[K,1]) + rangV*rand(K,1);
end

% 用于存储每个点被分配的cluster以及到质心的距离
clusterAssment = zeros(row,2);
clusterChange = true;
while clusterChange
    clusterChange = false;
    % 计算每个点应该被分配的cluster
    for i = 1:row
        % 这部分可能可以优化
        minDist = 10000;
        minIndex = 0;
        for j = 1:K
            distCal = distEclud(dataSet(i,:) , centSet(j,:));
            if (distCal < minDist)
                minDist = distCal;
                minIndex = j;
            end
        end
        if minIndex ~= clusterAssment(i,1)
            clusterChange = true;
        end
        clusterAssment(i,1) = minIndex;
        clusterAssment(i,2) = minDist;
    end

    % 更新每个cluster 的质心
    for j = 1:K
        simpleCluster = find(clusterAssment(:,1) == j);
        centSet(j,:) = mean(dataSet(simpleCluster‘,:));
    end
end
end

算法迭代过程如下

biCentSet =

-0.1036    0.0543
     0         0
     0         0
     0         0

第1个cluster被划分后的误差为:792.916857

bestClusterToSpilt =

 1

bestCentSet =

   -0.2897   -2.8394
    0.0825    2.9480

biCentSet =

   -0.2897   -2.8394
    0.0825    2.9480
     0         0
     0         0

第1个cluster被划分后的误差为:409.871545

第2个cluster被划分后的误差为:532.999616

bestClusterToSpilt =

 1

bestCentSet =

   -3.3824   -2.9473
    2.8029   -2.7315

biCentSet =

   -3.3824   -2.9473
    0.0825    2.9480
    2.8029   -2.7315
     0         0

第1个cluster被划分后的误差为:395.669052

第2个cluster被划分后的误差为:149.954305

第3个cluster被划分后的误差为:393.431098

bestClusterToSpilt =

 2

bestCentSet =

2.6265    3.1087
-2.4615    2.7874

biCentSet =

   -3.3824   -2.9473
    2.6265    3.1087
    2.8029   -2.7315
   -2.4615    2.7874

最终效果图

运用二分K-means算法进行聚类的时候,不同的初始质心聚类结果还是会稍微有点不同,因为实际上这也只是弱化随机质心对聚类结果的影响而已,并不能消除其影响,不过最终还是能收敛到全局最小。

时间: 2024-08-03 21:57:20

机器学习实战ByMatlab(四)二分K-means算法的相关文章

机器学习实战ByMatlab(二)PCA算法

PCA 算法也叫主成分分析(principal components analysis),主要是用于数据降维的. 为什么要进行数据降维?因为实际情况中我们的训练数据会存在特征过多或者是特征累赘的问题,比如: 一个关于汽车的样本数据,一个特征是"km/h的最大速度特征",另一个是"英里每小时"的最大速度特征,很显然这两个特征具有很强的相关性 拿到一个样本,特征非常多,样本缺很少,这样的数据用回归去你和将非常困难,很容易导致过度拟合 PCA算法就是用来解决这种问题的,其

机器学习实战ByMatlab(一)KNN算法

KNN 算法其实简单的说就是"物以类聚",也就是将新的没有被分类的点分类为周围的点中大多数属于的类.它采用测量不同特征值之间的距离方法进行分类,思想很简单:如果一个样本的特征空间中最为临近(欧式距离进行判断)的K个点大都属于某一个类,那么该样本就属于这个类.这就是物以类聚的思想. 当然,实际中,不同的K取值会影响到分类效果,并且在K个临近点的选择中,都不加意外的认为这K个点都是已经分类好的了,否则该算法也就失去了物以类聚的意义了. KNN算法的不足点: 1.当样本不平衡时,比如一个类的

机器学习实战ByMatlab(三)K-means算法

K-means算法属于无监督学习聚类算法,其计算步骤还是挺简单的,思想也挺容易理解,而且还可以在思想中体会到EM算法的思想. K-means 算法的优缺点: 1.优点:容易实现 2.缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢 使用数据类型:数值型数据 以往的回归算法.朴素贝叶斯.SVM等都是有类别标签y的,因此属于有监督学习,而K-means聚类算法只有x,没有y 在聚类问题中,我们的训练样本是 其中每个Xi都是n维实数. 样本数据中没有了y,K-means算法是将样本聚类成k个簇,具

《机器学习实战》学习笔记——k近邻算法

1.numpy中一些函数的用法学习 shape()用法: shape : tuple of ints The elements of the shape tuple give the lengths of the corresponding array dimensions.. shape返回一个元组,依次为各维度的长度.shape[0]:第一维长度,shape[1]:第二维长度. tile()用法: numpy.tile(A, reps) Construct an array by repea

《机器学习实战》之二分K-均值聚类算法的python实现

<机器学习实战>之二分K-均值聚类算法的python实现 上面博文介绍了K-均值聚类算法及其用python实现,上篇博文中的两张截图,我们可以看到,由于K-均值聚类算法中由于初始质心的选取,会造成聚类的局部最优,并不是全局最优,因此,会造成聚类的效果并不理想,为克服K-均值算法收敛于局部最小值的问题,就有了二分K-均值算法. 二分K-均值聚类算法 二分K均值算法是基本K均值算法的直接扩充,其基本思想是:为了得到K个簇,首先将所有点的集合分裂成两个簇,然后从这些簇中选取一个继续分裂,迭代直到产生

《机器学习实战》之K-均值聚类算法的python实现

<机器学习实战>之K-均值聚类算法的python实现 最近的项目是关于"基于数据挖掘的电路故障分析",项目基本上都是师兄们在做,我只是在研究关于项目中用到的如下几种算法:二分均值聚类.最近邻分类.基于规则的分类器以及支持向量机.基于项目的保密性(其实也没有什么保密的,但是怕以后老板看到我写的这篇博文,所以,你懂的),这里就不介绍"基于数据挖掘的电路故障分析"的思路了. 废话不多说了,开始正题哈. 基本K-均值聚类算法 基本K均值算法的基本思路为:首先选择

python机器学习实战(四)

python机器学习实战(四) 版权声明:本文为博主原创文章,转载请指明转载地址 www.cnblogs.com/fydeblog/p/7364317.html 前言 这篇notebook是关于机器学习中logistic回归,内容包括基于logistic回归和sigmoid分类,基于最优化方法的最佳系数确定,从疝气病症预测病马的死亡率.操作系统:ubuntu14.04  运行环境:anaconda-python2.7-jupyter notebook 参考书籍:机器学习实战和源码   noteb

机器学习实战读书笔记(二)k-近邻算法

knn算法: 1.优点:精度高.对异常值不敏感.无数据输入假定 2.缺点:计算复杂度高.空间复杂度高. 3.适用数据范围:数值型和标称型. 一般流程: 1.收集数据 2.准备数据 3.分析数据 4.训练算法:不适用 5.测试算法:计算正确率 6.使用算法:需要输入样本和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理. 2.1.1 导入数据 operator是排序时要用的 from numpy import * import operato

二分-k均值算法

首先我们都知道k均值算法有一个炒鸡大的bug,就是在很多情况下他只会收敛到局部最小值而不是全局最小值,为了解决这个问题,很多学者提出了很多的方法,我们在这里介绍一种叫做2分k均值的方法. 该算法首先将所有点作为一个簇,然后将该簇一分为二.之后选择其中一个簇继续进行划分,选择哪一个簇进行划分取决于哪个簇的sse是最大值.上述基于sse的划分过程不断重复,直到得到用户指定的簇数目为止. 将所有的点看成一个簇,当粗的数目小于k时,对每一个簇计算总误差,在给定的粗上进行k均值聚类(k=2),计算将该粗一