matlab 职坐标,机器学习入门之机器学习实战ByMatlab(四)二分K-means算法

news/2024/8/21 8:51:40

本文主要向大家介绍了机器学习入门之机器学习实战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 

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

$(function () {

$(‘pre.prettyprint code‘).each(function () {

var lines = $(this).text().split(‘\n‘).length;

var $numbering = $(‘‘).addClass(‘pre-numbering‘).hide();

$(this).addClass(‘has-numbering‘).parent().append($numbering);

for (i = 1; i <= lines; i++) {

$numbering.append($(‘

‘).text(i));

};

$numbering.fadeIn(1700);

});

});

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标人工智能机器学习频道!


http://lihuaxi.xjx100.cn/news/242491.html

相关文章

C++ 枚举类型基本知识

1.定义 enum <类型名> {<枚举常量表>};2.说明 关键字enum——指明其后的标识符是一个枚举类型的名字。 枚举常量表——由枚举常量构成。枚举常量只能以标识符形式表示&#xff0c;而不能是整型、字符型等文字常量。 非法定义&#xff1a; enum letter_set {a,d…

UVa11300 - Spreading the Wealth

题意 n个人围成一圈&#xff0c;每个人都有一定数量的金币&#xff0c;金币总数可被n整除&#xff0c;现可将手中金币给左右相邻的人&#xff0c;最终使每人手中的金币数相等&#xff0c;求最少转移的金币数量。 思路 设a[i]给了a[i-1]x1个金币&#xff0c;从a[i1]拿到x2个金币…

哪些人适合学习java技术

java技术在互联网行业一直都是非常重要的存在&#xff0c;学习java技术只会多不会少&#xff0c;那么目前哪些人适合学习java技术呢?来看看下面的详细介绍就知道了。 哪些人适合学习java技术? 1.在家待业人员&#xff0c;没有明确的目标&#xff0c;不知道自己想要什么&#…

Python字符串类型及操作总结

1.字符串表示 两种类型四种表示 单行-一对单引号或一对双引号 “python” ‘python’ 多行-一对三单引号或一对三双引号 ‘’’python’’’ “””python””” (三单引号形成的是字符串&#xff0c;但也可以用作多行注释) 如果字符串中出现双引号&#xff0c;则两边要用单引…

jquery获取当前时间

一、获取当前时间 new Date()方法---------得到结果是当前电脑时间如2011-11-6,10:07二、获取有个固定的时间方法---------var endtimenew Date("2013/10/01,18:25:00");三、时间转化成毫秒数----------endtime.getTime();四、获取当前的年份-----------endtime.getY…

用 cooking 搭建一个简单又优雅的 Vue 项目开发环境 (入门篇)

本文适合 Vue 的初学者&#xff0c;以及对 webpack 不熟悉的同学阅读。前提是你要会用基本的命令行、 Node 和 NPM&#xff0c;以及掌握 ES2015 的基础知识。本文都是在 macOS 环境下运行&#xff0c;要求使用 npm > 3, node > 4 的环境。我们会以 Vue 2.0 搭配 Webpack …

UI设计培训学习中必须掌握的设计原则

不管是刚开始学习UI设计或者已经在学习UI设计同学中&#xff0c;UI设计的设计原则都是非常重要的&#xff0c;需要大家去重点关注的&#xff0c;下面小编就为大家详细的介绍一下UI设计培训学习中必须掌握的设计原则。 UI设计培训学习中必须掌握的设计原则&#xff1a; 重复 在平…

php redis管理系统,php+redis实现小型的用户管理系统

1、redis.php &#xff0c;用于连接redis数据库//实例化$redis new Redis();//连接服务器$redis->connect("localhost");//授权$redis->auth("lamplijie");2、add.php&#xff0c;用于添加用户用户名&#xff1a;密码&#xff1a;年龄&#xff1a;3…