每天进步一点点《ML - K-means》

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

一:聚类
就我个人而言,学到了这里,是让我非常激动的事情,因为K-means这个算法是我学习到的第一个非监督学习算法,也是第一个聚类算法。
所谓的无监督学习,就是对于样本来说,我们不知道它的输出,或者不知道它的标签是什么,我们唯一知道的就是样本空间内,各个样本的特征向量。所谓聚类,就是通过某种算法,自动将在特征空间内相似的样本聚合在一起组成一个类簇(cluster),通过自动的样本聚类,帮助人们发现样本之间的分布和类群特征。
比如在文章分类中,通过提取众多关键词,组合特征的样本向量,通过比较之间的相似度和距离,自动将文章划分为不同不种类,比如新闻类,财经类,政治类,体育类等等。
再比如社交网络,通过给不同用户 “画像”,也就是给用户建立特征模型,通过聚类找到相似的群体,有助于商业决策和内容推荐等活动。

二:K-means算法
也就是有K个平均值点。啥意思呢?见我详细道来。先上菜,整起算法过程。
1) 在所有点中随机选出K个点作为簇中点(μ1, μ2, μ3, μ4, μ5…. , μk),暂且将K个簇编号为1, 2, 3, 4, 5, …… K,注意,大写的K是数量,小写的k是编号。
2) 计算出所有样本点x(i) 到所有簇中点μk 的距离D(x(i), μk)(可以是欧式距离,或者是曼哈顿距离),再找到距离点x(i)最近的μk,标记该样本的簇是c(i)=k。
3) 重新计算所有上一步骤得到的簇的中心点μk,
4) 重复步骤2和3。直到μk,不会再法还是能大的变化或不变为止,此时算法收敛了。

三:具体演示
下面我会用一个具体的例子来展示这个过程。
在这里插入图片描述
图中,有一群样本点,绿色的,我们现在想要对它们进行分类,有两个分类簇,分别是蓝色和红色的连个点,K=2,我们先随机选择了这两个中心点,作为起始中心。
1:第一轮迭代。
在这里插入图片描述

2:第二轮迭代。
在这里插入图片描述

3:第三轮迭代。
在这里插入图片描述

4:第四轮迭代。
在这里插入图片描述

从这里可以发现,聚类基本收敛了,所以到此可以停止了。
评价方法是:聚类中心点向量μ,基本不再变化。

计算过程如下:

clear all
clc

src_x1 = round((1 .+ 1.5 .* rand(1, 30)) .* 10) / 10;
src_y1 = round((2.5 .+ 1.3 .* rand(1, 30)) .* 10) / 10;;
src_x2 = round((3 .+ 1.5 .* rand(1, 30)) .* 10) / 10;;
src_y2 = round((4.5 .+ 1.3 .* rand(1, 30)) .* 10) / 10;;

src_x = [src_x1, src_x2]';
src_y = [src_y1, src_y2]';


% random to get samples and each tag(i) is to trainData(i, :)
% tag is to every sample. 
trainData = [src_x, src_y];
tag = zeros(size(trainData)(1), 1);

% ther are two clusters. K=2, set tag is belongs to set{
    
    1, 2}
% cluster_means(1) is to tag(1), cluster_means(2) is to tag(2)
K=2;

% randomly to pick two clusters center points
cluster_means = [3.0,3.7; 
				1.5, 4.5];
flagNum = [1:1:K]';

% color(01): no cluster or is to tag==0, color(2) is to tag==1, color(3) is to tag==2
color = ['g'; 'r'; 'b'];


itr = 6
for it=1:itr


	subplot(2, 3, it);
	hold on;

	% draw all points and cluster center points
	for i=1:size(trainData)(1)
		scatter(trainData(i, 1), trainData(i, 2), color(tag(i, 1)+1, 1), 'linewidth', 3);
	end;
	for i=1:size(cluster_means)(1)
		scatter(cluster_means(i, 1), cluster_means(i, 2), color(i+1), 'linewidth', 10);
	end;
	
	xlim([0,6]);
	ylim([2,6]);
	%axis equal;
	grid on;
	xlabel('x1');
	ylabel('x2');
	
	if it == 1
		title('Orign Samples','fontname','Times New Roman','Color','k','FontSize',24);
	else
		str = sprintf('%s : %d','iteration',it-1)
		title(str,'fontname','Times New Roman','Color','k','FontSize',24);
	end;


	% calculae each sample point to find the nearest cluster center point.
	for i=1:size(trainData)(1)
		
		% calculate the distance to each cluster center point.
		distance = sqrt(((trainData(i, :) .- cluster_means) .^ 2) * ones(2,1));
		
		% find the nearest cluster ponit and set this sample to this cluster.
		tmpDis = [distance, flagNum];
		sortDis = sortrows(tmpDis);
		
		tag(i) = sortDis(1, 2);
	end;
	
	
	% change each cluster center point.
	for k=1:size(cluster_means)(1)
		count = 0;
		count_point = zeros(1, size(trainData)(2));
		for i=1:size(tag)(1)
			if tag(i, 1) == k
				count_point = count_point .+ trainData(i, :);
				count++;
			end;
		end;
		cluster_means(k, :) = count_point ./ count;
	end;
	
	
end;

在这里插入图片描述

我们可以发现,我们的参数仅仅是一个K,而且收敛速度也挺快,也比较容易让人理解,原理和算法实现都简单。

但是这个K值不好把握,而且,容易受到噪声影响。

四:优化点

1) 初始化的优化:
k个初始化的簇中心的位置对于选择对最后的聚类结果和运行时间都有很大的影响,因此需要选择合适的k个质心。如果仅仅是完全随机的选择,有可能导致算法收敛很慢。K-Means++算法就是对K-Means随机初始化质心的方法的优化。
方法:
a) 在初始化阶段,先随机选择第一个样本点作为第一个簇的中心点μ1,
b) 计算其他样本点到μ1的的距离,
c) 找到距离较远的那个点,作为第二个簇的中心点μ2
d) 将步骤c和d重复执行,直到选择出K个初始化的簇中心点。
e) 用这几个初始化的中心点去做后续的K-means算法。能保证点和点之间的距离很大,显得分散地开,减少迭代次数,加快收敛速度。

2) 距离计算优化(elkan K-Means):
利用三角形规律,两边之和大于第三边,两边只差小于第三边。
如果我们有一个样本点x(i),和簇中心点μi和μj。如果我们算出了中心点之间距离D(μi, μj),以及x(i)到μ1的距离D(μi, x(i))。如果2* D(μi, x(i)) < D(μi, μj),那么我们就可以得到,样本点x(i)到簇中心点μi的距离是较近的。就不用计算另外个距离了D(μj, x(i))。

3) Mini Batch K-Means
当我们的样本集合数量很大的,特征个数也很大的的时候就会很耗费计算时间。于是每次随机取样一部分样本进行K-Means 算法。多运行几次这样的,取最优化的聚类。

猜你喜欢

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