K-means算法和KNN算法

版权声明:分享才能获得最大的价值 https://blog.csdn.net/qq_32252957/article/details/83794901

github: 智能算法的课件和参考资料以及实验代码

 

K-means是最为常用的聚类算法,该算法是将相似的样本归置在一起的一种无监督算法。采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。

算法主要步骤可描述如下:

  1. 随机产生K个初始聚类中心。
  2. 计算测试点到聚类中心的距离,选择距离最近的聚类中心将测试点归类。
  3. 更新每类的聚类中心。
  4. 重复步骤2、3迭代更新,直至聚类中心不再改变,或者新的聚类中心与前一步聚类中心的距离小于某个值

KNN算法是最简单的分类算法,如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。算法主要步骤可描述如下:

  1、计算已知类别数据集中的点与当前点之间的距离;

2、按照距离递增依次排序;

3、选取与当前点距离最小的k个点

4、确定k个点在所在类别的出现频率

5、返回k个点出现频率最高的类别作为当前点的预测分类

 

下面直接给出代码(matlab实现):

k-means算法:

clear all;close all; clc;
% 第一组数据
mul=[0,0]; % 均值
S1=[.1 0;0 .1]; % 协方差
data1=mvnrnd(mul, S1, 100); % 产生高斯分布数据
% 第二组数据
mu2=[1.25 1.25];
S2=[.1 0;0 .1];
data2=mvnrnd(mu2,S2,100);
% 第三组数据
mu3=[-1.25;1.25]
S3=[.1 0;0 .1]
data3=mvnrnd(mu3,S3,100)
% 显示数据
plot(data1(:,1),data1(:, 2),'b+');
hold on;
plot(data2(:,1),data2(:,2),'r+');
plot(data3(:,1),data3(:,2),'g+');
grid on; % 在画图的时候添加网格
% 三类数据合成一个不带标号的数据类
data=[data1;data2;data3];
N=3; % 设置聚类数目k的值
[m,n]=size(data); % 300x2矩阵
pattern=zeros(m,n+1);
center=zeros(N,n); % 初始化聚类中心 3x2
pattern(:,1:n)=data(:,:);
for x=1:N
	center(x,:)=data(randi(300,1),:); % 第一次随机产生聚类中心
end
while 1
	distance=zeros(1,N);
	num=zeros(1,N);
	new_center=zeros(N,n);
	for x=1:m
		for y=1:N 
			% 这里使用的是欧氏距离
			distance(y)=norm(data(x,:)-center(y,:)); % 计算每个样本到每个类中心的距离 
		end
		% min函数有三种调用形式 
		% min(A): 返回一个行向量,是每列最小值
		% [Y, U]=min(A): 返回行向量Y和U, Y向量记录A的每列的最小值,U向量记录每列最小值的行号
		% min(A, dim): dim取1或2.dim取1时,该函数与max(A)完全相同;dim为2时,返回列向量,其第
		% i个元素是A矩阵的第i行上的最小值
		[~,temp]=min(distance);
		pattern(x,n+1)=temp;
	end
	k=0;
	for y=1:N
		% 遍历所有样本,找到属于第y类的样本,并重新计算簇中心
		for x=1:m
			if pattern(x,n+1)==y
				new_center(y,:)=new_center(y,:)+pattern(x,1:n)
				num(y)=num(y)+1 % 计算第y类的所属样本个数,便于求均值
			end
		end
		new_center(y,:)=new_center(y,:)/num(y);
		if norm(new_center(y,:)-center(y,:))<0.1
			k=k+1
		end
	end
	if k==N
		break;
	else
		center=new_center
	end
end
[m,n]=size(pattern) % m=300,n=3

% 显示聚类后的数据
figure;
hold on;
for i=1:m
	% 属于不同类别的样本画成不一样的r、b、g颜色的*状,最终的簇中心为黑色圆圈
	if pattern(i,n)==1
		plot(pattern(i,1),pattern(i,2),'r*');
		plot(center(1,1),center(1,2),'ko');
	elseif pattern(i,n)==2
		plot(pattern(i,1),pattern(i,2),'g*');
		plot(center(2,1),center(2,2),'ko');
	elseif pattern(i,n)==3
		plot(pattern(i,1),pattern(i,2),'b*');
		plot(center(3,1),center(3,2),'ko');
	end
end 
grid on;

实验结果:

原始数据raw data                                                           由于起始的簇中心选取很重要,因此性能也会变化,下面是不好的结果

良好的聚类结果:

 

下面给出了简单的分类算法KNN(用于分类的数据github下载):

clear all;close all;clc;
load data; % 读取数据
Data = data;
% ?100个样本进行归?化处? min-max标准化方法[0,1]区间
% 缺点是当有新的数据加入时,max和min可能发生变化,需要重新定?
for i=1:100 
	for j=1:3
		Data(i,j)=(data(i,j)-min(data(:,j)))/(max(data(:,j))-min(data(:,j)));
	end
end
D1=Data(1:80,:);
D2=Data(81:100,:);
k=20; % 训练集是80个样本,测试集是20个样?
for i=1:20
	temp=D2(i,1:3)
	for j=1:80 % 计算每个测试样本到训练样本的距离向量
		distance(j)=norm(temp-D1(j,1:3));
	end
	[distance1,index]=sort(distance); %升序排列
	In=index(1:k); % 统计周围20个训练样本的类别情况
	l1=length(find(D1(In,4)==1));
	l2=length(find(D1(In,4)==2));
	l3=length(find(D1(In,4)==3));
	[maxl,class(i)]=max([l1,l2,l3]); % class(i)是每个样本所属类别的20行向?
end
class
ratio=length(find((class'-D2(:,4))==0))/20 % 统计正确率是%90

可以看到分类效果不是很好,后面我们会利用PCA和异常数据监测来提高分类的性能。这里只是介绍最简单的算法

 

总结:

K-means缺点:

(1) K是事先给定的,K值的选定是非常难以估计的

(2) 对异常数据很敏感。在计算质心的过程中,如果某个数据很异常,在计算均值的

    时候,会对结果影响非常大

 

KNN优缺点:

优点:

    精度高,对异常值不敏感,无数据输入假定

缺点:

    计算量大,样本不平衡时分类结果误差大

改进: 事先对样本进行剪辑,除去对分类作用不大的样本权值的方法(和该样本距离小的邻域权值大)

 

猜你喜欢

转载自blog.csdn.net/qq_32252957/article/details/83794901
今日推荐