K-mean(多维度)聚类算法(matlab代码)

article/2025/10/21 18:49:46

申明: 仅个人小记。 Email: officeforcsdn@163.com

目录

        • 效果演示
          • 二维度
          • 三维度
        • k-mean 算法思想简要说明
        • 代码分析
          • 二维度k-mean代码
          • 三维度k-mean代码
          • 多维度k-mean代码
          • 功能使用示范
          • 后期函数接口改造 (借助matlab中cell结构实现)
          • 新的函数接口使用范例
        • 小结

效果演示

二维度

(1) K = 6; 参与元素个数为1000

(2) K = 7; 参与元素个数为1000

三维度

(1)

(2)

k-mean 算法思想简要说明

给定1000个二维坐标点,现在指定要把它们分为k类,面对这样的情况该怎么处理?能想到的思路可能是穷举法,规规矩矩的从这1000个二维坐标点覆盖的二维面积中挑出k个点(我们称之为种子元素),然后遍历所有的元素点(这里指的就是1000个给定的点),对每一个元素进行判定类别,即判定每一个元素应该是归为k个类中哪一个类,并把该元素加入在被判定的类中。判断的规则就是,当前元素和k个种子之间的欧几里得距离最短的那个种子所代表的类就是当前元素应该加入的类。所有的元素遍历完毕,我们这是得到K组元素集合,即原来的元素被划分为k类了。这是我们计算每一组的方差,我目前认为应该是不停的用上述方法,得到分类,然后计算方差,最终,要找到每一个类方差最小的情况,这是认为是最优的分类,分类完毕。
显然,上述最大的弊端就是计算量很大,一点优化的成分都没有。k-mean算法思想中提出:但我们得到k组类别集合,计算k组每一组的中心点(方法就是计算均值点),每一组都得到中心点。这时,我们认为k组中心点为新的种子点。如果本次计算得到的种子点和之前的种子点是完全一致的,那么说明我们已经分类完毕了。如果不一致,如果不一致,我们就会基于的到的新的种子,再进行上述的操作,知道新计算的种子点和上一次的种子点完全匹配。另外,提一下关于第一次选择种子点的问题,应该是第一次选择的种子应该是来源于源数据样本元素(写代码的时候发现有必要这样做,如果不这样,在结果中会出现某一个类别的成员数量为0,显然,这是不合理的。成员个数为0的类别意味着这个类别是不存在,显然是不符合要分为k类的要求)。

代码分析

二维度k-mean代码
function [ resX,resY,record] = FunK_mean( x,y,k )
% 功能:
%     实现k-mean聚类算法
% 输入:
%     二维数据,分别用x,y两个一维向量代表两个维度
%     k 是分成的类别的数量
% 输出:
%     k行的两个矩阵
%     对应同样的第n行,存放着第n类的所有元素
%     record: 记录着每一行的有效元素的个数j = 1;% 下面是预分配一些空间% seedX 和 seedY 中存放着所有种子seedX = zeros(1,k);seedY = zeros(1,k);oldSeedX = zeros(1,k);oldSeedY = zeros(1,k);resX = zeros(k,length(x));resY = zeros(k,length(x));% 用来记录resX中每一行有效元素的个数record = zeros(1,k); for i = 1:k % 产生k个随机种子, 注意: 随机种子是来自元素集合seedX(i) = x(round(rand()*length(resX)));seedY(i) = y(round(rand()*length(resX)));% 为保证种子不重叠if (i > 1 && seedX(i) == seedX(i-1) && seedY(i) == seedY(i-1))i = i -1; % 重新产生一个种子endendseedXseedYwhile 1record(:) = 0; % 重置为零resX(:) = 0;resY(:) = 0;for i = 1:length(x) % 对所有元素遍历% 下面是判断本次元素应该归为哪一类,这里我们是根据欧几里得距离进行类别判定% k-mean算法认为元素应该归为距离最近的种子代表的类distanceMin = 1;for j = 2:kif (power(x(i)-seedX(distanceMin),2)+power(y(i)-seedY(distanceMin),2))... > (power(x(i)-seedX(j),2) + power(y(i)-seedY(j),2))distanceMin = j;endend% 将本次元素点进行类别归并resX(distanceMin,record(distanceMin)+1) = x(i);resY(distanceMin,record(distanceMin)+1) = y(i);record(distanceMin) = record(distanceMin) + 1;endoldSeedX = seedX;oldSeedY = seedY;% 移动种子至其类中心recordfor i = 1:kif record(i) == 0continue;endseedX(i) = sum(resX(i,:))/record(i);seedY(i) = sum(resY(i,:))/record(i);end% 如果本次得到的种子和上次的种子一致,则认为分类完毕。if mean([seedX == oldSeedX seedY == oldSeedY]) == 1 % 这句话所想表达的意思就是 if seedX == oldSeedX && seedY == oldSeedYbreak;endend% 下面代码只是对resX,resY所占用的内寸大小进行简单的优化maxPos = max(record);resX = resX(:,1:maxPos);resY = resY(:,1:maxPos);
end
三维度k-mean代码
function [ resX,resY, resZ,record] = FunK_mean3D( x,y,z,k )
% 功能:
%     实现三维空间k-mean聚类算法
% 输入:
%     三维数据,分别用x,y,z两个一维向量代表两个维度
%     k 是分成的类别的数量
% 输出:
%     k行的两个矩阵
%     对应同样的第n行,存放着第n类的所有元素
%     record: 记录着每一行的有效元素的个数j = 1;% 下面是预分配一些空间% seedX 和 seedY 中存放着所有种子seedX = zeros(1,k);seedY = zeros(1,k);seedZ = zeros(1,k);oldSeedX = zeros(1,k);oldSeedY = zeros(1,k);oldSeedZ = zeros(1,k);resX = zeros(k,length(x));resY = zeros(k,length(x));resZ = zeros(k,length(x));% 用来记录resX中每一行有效元素的个数record = zeros(1,k); for i = 1:k % 产生k个随机种子, 注意: 随机种子是来自元素集合seedX(i) = x(round(rand()*length(resX)));seedY(i) = y(round(rand()*length(resX)));seedZ(i) = z(round(rand()*length(resX)));% 为保证种子不重叠if (i > 1 && seedX(i) == seedX(i-1) && seedY(i) == seedY(i-1) && seedZ(i) == seedZ(i-1))i = i -1; % 重新产生一个种子endendwhile 1record(:) = 0; % 重置为零resX(:) = 0;resY(:) = 0;resZ(:) = 0;for i = 1:length(x) % 对所有元素遍历% 下面是判断本次元素应该归为哪一类,这里我们是根据欧几里得距离进行类别判定% k-mean算法认为元素应该归为距离最近的种子代表的类distanceMin = 1;for j = 2:kif (power(x(i)-seedX(distanceMin),2)+power(y(i)-seedY(distanceMin),2)+power(z(i)-seedZ(distanceMin),2))... > (power(x(i)-seedX(j),2) + power(y(i)-seedY(j),2)+power(z(i)-seedZ(j),2))distanceMin = j;endend% 将本次元素点进行类别归并resX(distanceMin,record(distanceMin)+1) = x(i);resY(distanceMin,record(distanceMin)+1) = y(i);resZ(distanceMin,record(distanceMin)+1) = z(i);record(distanceMin) = record(distanceMin) + 1;endoldSeedX = seedX;oldSeedY = seedY;oldSeedZ = seedZ;% 移动种子至其类中心recordfor i = 1:kif record(i) == 0continue;endseedX(i) = sum(resX(i,:))/record(i);seedY(i) = sum(resY(i,:))/record(i);seedZ(i) = sum(resZ(i,:))/record(i);end% 如果本次得到的种子和上次的种子一致,则认为分类完毕。if mean([seedX == oldSeedX seedY == oldSeedY seedZ == oldSeedZ]) == 1 % 这句话所想表达的意思就是 if seedX == oldSeedX && seedY == oldSeedYbreak;endendmaxPos = max(record);resX = resX(:,1:maxPos);resY = resY(:,1:maxPos);resZ = resZ(:,1:maxPos);
end
多维度k-mean代码

返回值res矩阵内容举例示意图:
在这里插入图片描述

function [ res, record] = FunK_meanPolyD(data,k )
% 功能:
%     实现多维空间k-mean聚类算法
% 输入:
%     data是d*n规格的矩阵,其中d代表维度,n代表样本的数量
%     k 是分成的类别的数量
% 输出:
%     res 是行数为(d*k), 列数为record中最大元素值
%	  对于res的行数为d*k的解释: 
%		1:d 是对应着第一类别元素
%		d+1:2*d 是对应着第二类别元素 
%			··· 
%		d*(k-1)+1:d*k 是对应着第k类别元素
%
%     record规格为1*k,记录着每一类别的有效元素的个数j = 1;% 下面是预分配一些空间% seedX 和 seedY 中存放着所有种子[h w] = size(data);cnt = w; % 输入元素的数量cntOfDimension = h; % d 中存放着本次处理数据的维度%seed 中存放种子,每一行代表种子所在的一个维度,每一列是一个种子向量seed = zeros(cntOfDimension,k);oldSeed = zeros(cntOfDimension,k);% 结果矩阵res中,数据存放规则:%   以d行为一个单位,总共k个d行%   第一个d行数据存放着第一类元素集合,其他同理res = zeros(k*cntOfDimension,cnt); % 用来记录resX中每一行有效元素的个数record = zeros(1,k); r = 0;for i = 1:k % 产生k个随机种子, 注意: 随机种子是来自元素集合t = round(rand()*cnt);% 为保证种子不重叠if i > 1 && t == ri = i - 1;continue;endseed(:,i) = data(:,t);r = t;endwhile 1record(:) = 0; % 重置为零res(:) = 0;for i = 1:cnt % 对所有元素遍历% 下面是判断本次元素应该归为哪一类,这里我们是根据欧几里得距离进行类别判定% k-mean算法认为元素应该归为距离最近的种子代表的类distanceMin = 1; % distanceMin 中存放着最短欧几里得距离的种子点的下标for j = 2:k% 计算高维度的欧几里得距离a = 0;b = 0;for row = 1:cntOfDimensiona = a + power(data(row,i)-seed(row,distanceMin),2);b = b + power(data(row,i)-seed(row,j),2);endif a > bdistanceMin = j;endend% 将本次元素点进行类别归并row = (distanceMin-1)*cntOfDimension + 1;res(row:row+cntOfDimension-1,record(distanceMin)+1) = data(:,i);record(distanceMin) = record(distanceMin)+1;end%recordoldSeed = seed;% 移动种子至其类中心for col = 1:kif record(col) == 0continue;end% 计算新的种子位置row = (col-1)*cntOfDimension + 1;seed(:,col) = sum(res(row:row+cntOfDimension-1,:),2)/record(col);end% 如果本次得到的种子和上次的种子一致,则认为分类完毕。if mean(seed == oldSeed) == 1break;endendmaxPos = max(record);res = res(:,1:maxPos);
end
功能使用示范
% k-mean算法在思想上还是存在弊端的
% k-mean算法是基于欧几里得空间距离进行基本判定的,而实际状况中不一定就是要以欧几里得空间距离作为判断基础的% 下面是二维k-mean
clear all
close all
t = 1000;%指定样本元素个数
x = rand(1,t);% 产生样本数据
y = rand(1,t);
k = 7;% 指定类别数量
% 
[resX,resY,record] = FunK_mean(x,y,k);% record 中存放着每一个类别组的成员数量 
% 注意为了编写方便,resX,resY 是以二维矩阵的形式呈现
% resX(i,:) 和resY(i,:) 表示第i个类别组的所有成员,
% 但有效成员的数目不一定等于length(resX(i,:)),而是等于record(i)
% 多余的空位是用零来填充的
hold on
for i = 1:length(record)plot(resX(i,1:record(i)),resY(i,1:record(i)),'*')
end
% 下面是标记出每一个类别的类别代表点
for i = 1:length(record)plot(mean(resX(i,1:record(i)),2)',mean(resY(i,1:record(i)),2)','Marker','square','Color','k','MarkerFaceColor','k','LineStyle','none')
end
hold off% % 三维度k-mean
% 
% clear all
% close all
% t = 1000;
% x = rand(1,t);
% y = rand(1,t);
% z = rand(1,t);
% k = 5;
% 
% [resX resY resZ record] = FunK_mean3D(x,y,z,k);
% 
% for i = 1:length(record)
%     plot3(resX(i,1:record(i)),resY(i,1:record(i)),resZ(i,1:record(i)),'*')
%     hold on
% end
% % 下面是标记出每一个类别的类别代表点
% for i = 1:length(record)
%     plot3(mean(resX(i,1:record(i)),2)',mean(resY(i,1:record(i)),2)',mean(resZ(i,1:record(i)),2)','Marker','square','Color','k','MarkerFaceColor','k','LineStyle','none')
% end%下面是多维 k-mean演示部分,包括2维,3维度,高维度
clear all
close all
t = 2000;
d = 3;
data = rand(d,t);
k = 5;
[res, record] = FunK_meanPolyD(data,k);[h, w] = size(res);
if h/k == 2hold onfor i = 1:kplot(res(i*2-1,1:record(i)),res(i*2,1:record(i)),'*')plot(mean(res(i*2-1,1:record(i)),2),mean(res(i*2,1:record(i)),2),'Marker','square','Color','k','MarkerFaceColor','k','LineStyle','none')endhold off
elseif h/k == 3for i = 1:kplot3(res(i*3-2,1:record(i)),res(i*3-1,1:record(i)),res(i*3,1:record(i)),'*')plot3(mean(res(i*3-2,1:record(i)),2),mean(res(i*3-1,1:record(i)),2),mean(res(i*3,1:record(i)),2),'Marker','square','Color','k','MarkerFaceColor','k','LineStyle','none')hold on%注意:hold on 要写在plot3之后,这样三维图形才会正常绘制endhold off
elsedisp(['结果维度大于3维,不能进行绘制'])
end
后期函数接口改造 (借助matlab中cell结构实现)
function [res_cell, centroid] = FunK_meanPolyD(data,k )
% 输入:
%      data : m * n  m是数据的维度,n是数据的数量
%      k : 类别数量
% 输出:
%     res_cell:  k个cell,每个cell中存放着该类别成员的在data中的下标
%   centroid : 每个类别中心点 m*k 格式的矩阵,每一列代表一个类别的中心点% 下面是预分配一些空间% seedX 和 seedY 中存放着所有种子[dim,n] = size(data);%seed 中存放种子,每一行代表种子所在的一个维度,每一列是一个种子向量seed = zeros(dim, k);oldSeed = zeros(dim, k);res = zeros(k,n);% k 行,一行代表一个类别,每一行存放成员标号(在data中的下标)record = zeros(1,k);% 用来记录res 中每一行有效成员的个数res_cell= cell(1,k);%% 随机初始化种子,这里保证随机种子各不相同tt = zeros(1,k);for i = 1:kflag = 1;while flagt = round(rand()*n);flag = 0;for j = 1:kif t == tt(j)flag = 1;break;endendendtt(i) = t;seed(:,i) = data(:,t);end%%  进入kmeans收敛过程while 1record(:) = 0; % 重置为零for i = 1:n % 对所有元素遍历distMin = 1; % distMin 中存放着最短欧几里得距离的种子点的下标for j = 2:k% 计算高维度的欧几里得距离a = dot(data(:,i)-seed(:,distMin),data(:,i)-seed(:,distMin));b = dot(data(:,i)-seed(:,j),data(:,i)-seed(:,j));if a > bdistMin = j;endendrecord(distMin) = record(distMin)+1;res(distMin,record(distMin)) = i;endoldSeed = seed;% 计算新的种子节点seed(:) = 0;for i = 1:k % 第i个类别for j = 1:record(i) % 第i个别中的每个成员 seed(:,i) = seed(:,i) + data(:,res(i,j));endseed(:,i) = seed(:,i)/record(i); % 计算中心点endif seed == oldSeed% 用cell对最后一次分组结果进行打包for i =1:kres_cell{1,i} = res(i,1:record(i)); endcentroid = seed;break; % 退出kmeans收敛过程endend
end
新的函数接口使用范例
close all
x = [1 1 2 2 4 5 5];
y = [1 2 1 3 5 5 3];
k = 2;% 指定类别数量
data = [x; y];
[dim, n] = size(data);
[res_cell,centroid] = FunK_meanPolyD(data,k)figure;
for i = 1:kt = res_cell{i};% t 中存放第i类别所有成员在原数据data中的下标tt = data(:,t); % tt 则是根据t中提供的下标,在data中将第i类别成员全部取出来,放到tt中if dim == 2 %绘制二维情况plot(tt(1,:),tt(2,:),'*');hold onplot(centroid(1,i),centroid(2,i),'Marker','square','Color','k','MarkerFaceColor','k','LineStyle','none')elseif dim == 3 % 绘制三维情况plot3(tt(1,:),tt(2,:),tt(3,:),'*')hold onplot3(centroid(1,i),centroid(2,i),centroid(3,i),'Marker','square','Color','k','MarkerFaceColor','k','LineStyle','none')end    grid on
end

小结

(1) k-mean缺点: 需要指定k,并不能自动合理的对给定的数据进行分类
(2) 优点:思想还是很棒的,尤其是基于新的种子点进一步归类这一思想,这一步骤很好的利用了已经计算过的结果,而不是每一次都是从头开始。
(3) 如果能够自动分类,我觉得也可以这种能力划分到盲源分离领域了。
(4) k-mean算法在思想上还是存在弊端的。我是这样想的:k-mean算法是基于欧几里得空间距离进行基本判定的,而实际状况中不一定就是要以欧几里得空间距离作为判断基础的。这一想法的产生,是因为我想到了数字图像里面RGB空间模型里面,不能用欧几里得距离的大小来衡量两种颜色的相近程度。


http://chatgpt.dhexx.cn/article/YAUQiuh8.shtml

相关文章

k-Means——经典聚类算法实验(Matlab实现)

聚类算法—k-Means实验 k-平均(k-Means),也被称为k-均值,是一种得到最广泛使用的聚类算法[1]. k-Means算法以k为参数,把n个对象分为k个簇,使得簇内具有较高的相似度。 实验目的 了解常用聚类算法及其优缺…

MATLAB K-means聚类的介绍与使用

K-means算法是硬聚类算法 ,是典型的基于原型的目标函数 聚类方法的代表,它是数据点到原型的某种距离作为优化的目标函数,利用函数求极值的方法得到迭代运算的调整规则。K-means算法以偶是距离 作为相似度测度,它是求对应某一初…

MatLab Kmeans聚类

机器学习以及人工智能的学习需要扎实的数学功底才能走的更远,爬的更高,所以打好数学基础是关键,但无论工作学习都没有充足的时间去拿着书本一个字一个字的去学习了,这里我建议大家找几个比较靠谱入门的机器学习或者人工智能学习平…

聚类分析(二)k-means及matlab程序

1.介绍 k-means是一种常见的基于划分的聚类算法。划分方法的基本思想是:给定一个有N个元组或者记录的数据集,将数据集依据样本之间的距离进行迭代分裂,划分为K个簇,其中每个簇至少包含一条实验数据。 2.k-means原理分析 2.1工作原…

数据挖掘实验(七)Matlab实现聚类算法【clusterdata / kmeans】

本文代码均已在 MATLAB R2019b 测试通过,如有错误,欢迎指正。 另外,这次实验都是调用Matlab现成的函数,没什么技术含量。 (一)聚类分析的原理 聚类是将数据分类到不同的类或者簇这样的一个过程&#xff…

K-means聚类 —— matlab

目录 1.简介 2.算法原理 3.实例分析 3.1 读取数据 3.2 原理推导K均值过程 3.3 自带kmeans函数求解过程 完整代码 1.简介 聚类是一个将数据集中在某些方面相似的数据成员进行分类组织的过程,聚类就是一种发现这种内在结构的技术,聚类技术经常被称为…

聚类分析的Matlab 程序—系统聚类(附有案例分析)

聚类分析的Matlab 程序—系统聚类 (1)计算数据集每对元素之间的距离,对应函数为pdistw. 调用格式:Ypdist(X),Ypdist(X,’metric’), Ypdist(X,’distfun’),Ypdist(X,’minkowski’,p) 说明:X是m*n的矩阵,metric是计算距离的方法选项&…

如何运用MATLAB实现K-MEANS聚类分析

由于自己最近在学习聚类分析,也算是一个入门,相当于将自己这段时间的学习成果进行一个总结,分享给更多打算学习聚类分析或者需要用到聚类分析的同学们~ 在了解K-MEANS聚类分析之前,我们首先明确聚类的含义,聚类是将数…

Matlab实现Kmeans聚类算法

1.Kmeans聚类算法简介 kmeans聚类算法是一种迭代求解的聚类分析算法。其实现步骤如下: (1) 随机选取K个对象作为初始的聚类中心 (2) 计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。 (3) 聚类中心以及分配给它们的对象…

k-means算法实例(聚类分析)matlab实现

例子如下: 假设数据挖掘的任务是将如下的8个点(用(x,y)代表位置)聚类为3个簇。 距离是欧氏距离。假设初始我们选择,和分别为每个簇的中心,用k-均值算法给出: a)在第一轮…

MATLAB层次聚类分析

实验题目 给出六个民族的出生死亡率,和他们的平均寿命,如下表所示 出生死亡率(%)平均寿命15.8070.5927.4467.1438.1165.48410.2158.8859.5159.8869.8160.47 MATLAB代码 %聚类分析 %步骤 %1.样本标准化 %2.计算各个样本之间的距…

matlab之聚类分析

文章目录 1.原理:2.数据:3.效果图:4.分类结果:5.分类代码: 1.原理: 聚类分析是根据在数据中发现的描述对象及其关系的信息,将数据对象分组。目的是,组内的对象相互之间是相似的&…

Matlab聚类分析(Kmeans)

提示:本文为记录学习聚类分析的一个过程,仅供参考,有不足之处还望提出 目录 前言一、原始数据二、数据处理与结果输出1.标准化与提取2.可视化3.簇数判别4.最终输出 总结 前言 本次样本中的片段数据涉及到多个故障原因,目的在于通…

Python语音信号处理

个人博客:http://www.chenjianqu.com/ 原文链接:http://www.chenjianqu.com/show-44.html 语言信息是多种信息的混合载体 ,其中包括内容信息、说话人信息和情感信息。 本文介绍了一些语音的基本知识,和使用Python进行处理。 时域…

语音信号处理1 ----- 基础知识

语音信号处理1 ----- 基础知识 1. 语音信号处理的目的:2. 语音发音和感知系统2.1 语音发音系统2.2 语音感知系统(听觉系统)2.2.1 听觉系统2.2.2 听觉特性 2.3 语音信号生成的数学模型 3. 语音基本概念及参数4. 语音信号数字化处理参考 1. 语音…

语音信号处理入门入籍和课程推荐

欢迎关注我的公众号,微信搜一搜【音频信号处理那些事儿】获取更多信息。 由于看网上关于语音信号处理的入门书籍和课程推荐的比较少,同时相关的领域人员也比较少,所以建了这个公众号,欢迎各位同仁指正交流,谢谢。 本…

前端语音信号处理

1、语音活动检测 语音活动检测(Voice Activity Detection, VAD)用于检测出语音信号的起始位置,分离出语音段和非语音(静音或噪声)段。VAD算法大致分为三类:基于阈值的VAD、基于分类器的VAD和基于…

语音信号处理及特征提取

1.信号处理基础 模拟信号->数字信号转化 步骤:采样和量化 奈奎斯特定律 :采样频率大于信号中最大频率的二倍 即在原始信号的一个周期中,至少要采样两个点,才能有效杜绝频率混叠问题。 信号进行离散傅里叶变换的条件&#x…

MATLAB语音信号处理系统GUI

基于MATLAB的语音信号处理 【摘 要】 Matlab语音信号处理是指利用matlab软件对音频信号进行读取,并对音频信号进行采样分析及离散傅里叶变换,以方便对其在频域上进行调制滤波等相关的操作。本次实验在提取音频信号后会对该信号使用在MATLAB软件中设计的…

《语音信号处理》 语音识别章节 读书笔记

两本书,《语音信号处理》赵力编和《语音信号处理》韩纪庆编。强烈推荐韩纪庆版本,知识点很全面,可以作为语音识别的入门中文书籍,章节很也短,很快就入门了。 P34 HMM是一个双内嵌式随机过程,由两个随机过程…