k-means聚类算法及matlab实现(简单实现)

k-means简介

  k-means算法也称k均值算法,是一种常用的聚类算法。聚类算法是研究最多、应用最广的一种无监督学习算法。
  聚类试图将数据集中的样本划分为若干个通常是不相交的子集,每个子集称为一个“簇”。通过这样的划分,每个簇里的样本可能具有一些潜在的、共同的特质。
  例如,对于给定样本集D={x1,x2,x3,…,xm}包含m个无标记样本,其中每个样本xi是一个n维的特征向量,聚类算法将样本集D划分为k个不相交的簇。其中,k个簇之间互不相交,且k个簇的并集为D。

k-means原理

k-means的伪代码

输入:样本集D = {x1,x2,x3,...,xm};
		   聚类簇数k.
过程:
从D中随机抽取k个样本作为初始均值向量{u1,u2,...,uk}
repeat
	初始化Cl = ∅(1≤l≤k)
	for i = 1:m
		计算样本xi与各均值向量uj(1≤j≤k)的距离d;
		根据距离最近的均值向量确定xi的簇标记;
		将样本xi划入相应的簇Cl;
	end
	for j = 1:k
		计算新的均值向量new_uj:对簇中每个样本求和/簇中样本的个数
		if new_uj ≠ uj
			将当前均值向量uj更新为new_uj
		else
			保持当前均值向量不变
		end
	end
until 当前均值向量均未更新
输出:簇划分为C = {C1,C2,...,Ck}

k值的选取

  有手肘法和轮廓系数法两种方法。这里简单介绍手肘法。
  手肘法的核心指标是SSE(Sum of Squared Errors),误差平方和
S S E = ∑ i = 1 k ∑ x ∈ C i ∣ ∣ x − μ i ∣ ∣ 2 2 SSE=\sum_{i=1}^{k}\sum_{x\in C_i}||x-\mu_i||_2^2 SSE=i=1kxCixμi22
其中,Ci是第i个簇,x是Ci中的样本点,μi是Ci的质心(Ci中所有样本的均值)。直观来看,该式是求当前的k值所对应的簇内的各个样本点到中心点欧式距离的平方和,该数值能体现出聚类后各个簇中样本点的密集程度,即SSE值越小,各个簇中的样本点越密集。
  对K值进行迭代,分别计算出相应的SSE。随着k值的增大,SSE会随之减小。这是因为随着k值的增大,样本会被划分得更加细致,每个簇就会更加紧凑。
  SSE的值会随着K值的增大而不断减小,直到k值与样本集中样本点的个数相等,此时SSE达到最小值。显然,并不是SSE的值越小,所选的K值就越合理。
  观察SSE随K值变化而变化的图像,分析K最合理的取值。(代码在后面放出来)
SSE—K图像
  从图像上看,当K值小于3时,SSE下降的幅度很大;而当K值大于3之后SSE下降的幅度大幅减小,这说明K值已经超过了最“合理”的值,从而导致每次减小K所带来的“收益”大幅减小,因此最佳的K值为3。由于图像看起来像手肘,因此这种选取最佳K值的方式被称为“手肘法”。

k-means的实现

  首先编写一个计算“有序属性”距离的函数,也可以使用matlab中自带的pdist或者是norm函数,推荐使用norm。

function dist = cal_dist(X,p)
%计算两个样本点之间的闵可夫斯基距离,当p=2时即为欧氏距离,当p=1时即为曼哈顿距离
dim = size(X);
sum = 0;
for i = 1:dim(2)
    sum = sum + abs(X(1,i)-X(2,i))^p; 
end
dist = sum^(1/p);
end

  再写一个归一化处理数据的函数。

function data = normalization(x)
%归一化处理数据
d = size(x);
data = zeros(d(1),d(2));
for i = 1:d(2)
    l = x(:,i);
    data(:,i) = (l - min(l))/(max(l)-min(l)); 
end
end

  然后进入正题。

function [index,C,sumd] = Kmeans(sample, k, threshold, n)
%K均值算法
%C:k个簇中心
%index:聚类后每个样本的标记
%sumd:样本点到相应的簇心的距离
%sample:需要进行聚类的样本
%k:划分簇的个数
%threshold:差异度阈值
%n最大迭代次数
iter = 0;
dim = size(sample);
index = zeros(dim(1), 1);
dist = zeros(k, 1);
C = sample(randperm(dim(1), k), :);
while 1
    sumd = zeros(dim(1), 1);
    for i = 1:dim(1)
        for j = 1:k
            X = [sample(i, :);C(j, :)];
            dist(j) = cal_dist(X, 2);
        end
        [d, idx] = min(dist);
        sumd(i) = d;
        index(i) = idx;
    end
    new_C = zeros(k, dim(2));
    c = 0;
    for i = 1:k
        count = 0;
        for j = 1:dim(1)
            if index(j) == i
                count = count + 1;
                new_C(i, :) = new_C(i, :) + sample(j, :);
            end
        end
        new_C(i, :) = new_C(i, :) / count;
        Y = [new_C(i, :);C(i, :)];
        if cal_dist(Y, 2)<= threshold
            c = c + 1;
        end
    end
    iter = iter + 1;
    if c == k
        break
    elseif iter > n
        break
    else
        C = new_C;
    end
end
end

  编写一个函数打印K-SSE图像,K值的选取理念已在上文提过。

function Visualize_SSE(sample, k)
%查看SSE随K值变化而变化的图像
dim = size(sample);
coordinate = zeros(k, 2);
for i = 1:k
    coordinate(i, 1) = i;
    if i == 1
        avg = mean(sample);
        d = zeros(dim(1), 1);
        for j = 1:dim(1)
            X = [sample(j, :);avg];
            d(j,1) = cal_dist(X, 2);
        end
        coordinate(i, 2) = sum(d);
    else
        [~, ~, sumd]=Kmeans(sample, i, 0.1, 9000);
        sumd = sumd.^2;
        coordinate(i, 2)=sum(sumd);
    end
end
plot(coordinate(:, 1),coordinate(:, 2))
xlabel('K')
ylabel('SSE')
end

  通过分析得出最佳的K值为3,下面编写一个脚本看一下聚类效果(matlab初学者表示不清楚还有哪些数据集只好用fisheriris中meas的前两维来代替。并不是说聚类算法不能对高维空间的数据进行聚类,选择两个维度是为了结果的可视化,也可以选择三个维度。)

load fisheriris
data = normalization(meas); 
[idx,C,~] = Kmeans(data(:,1:2),3,0,5000);
figure
gscatter(data(:,1),data(:,2),idx,'bgm')
hold on
plot(C(:,1),C(:,2),'kx')
legend('Cluster 1','Cluster 2','Cluster 3','ClusterCentroid')

  聚类效果:
在这里插入图片描述
  本文为了顺带提一嘴距离度量因此自己十分简陋的写了一个计算距离的函数,实际上使用matlab中自带的norm或者pdist即可。
  本文只是对k均值进行了一个简单的介绍。聚类任务相关的性能度量和距离度量还有很多;此外,如何对高维空间中的数据进行聚类本文也不做讨论。

代码

  https://github.com/Qyokizzzz/AI-Algorithm/tree/master/K-means

  • 87
    点赞
  • 791
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
### 回答1: k-means聚类算法是一种常用的无监督学习算法,可以将数据集分成k个簇,每个簇内的数据点相似度较高,不同簇之间的数据点相似度较低。Matlab提供了k-means聚类算法实现,可以通过调用kmeans函数来实现。该函数需要输入数据集和簇的个数k,输出每个数据点所属的簇的编号以及簇的中心点坐标。可以通过调整k的值来控制簇的个数,从而得到不同的聚类结果。 ### 回答2: K-means算法是一种基础的聚类算法,常用于数据分析、模式识别和图像处理等领域。在Matlab中,实现K-means聚类算法非常简单。 首先,我们需要准备数据集和确定聚类的个数K。数据集可以是一组有标记数据,也可以是无标记数据。而K值则需要预先设置,它表示将数据集划分成K个簇。 在Matlab中,可以使用kmeans函数来实现K-means聚类算法。以下是一个基本的实现步骤: 1. 载入数据集。数据集可以用Matlab内置的数据类型,也可以从外部文件中读取。 2. 预处理数据集。这通常包含特征缩放、标准化、均值化等操作。这些操作有助于提高聚类效果。 3. 调用kmeans函数。该函数需要传入两个参数:数据集和K值。此外,还可以设置其他一些可选参数,如最大迭代次数、初始聚类中心等。 4. 获取聚类结果。聚类结果包含每个数据点被划分到的簇编号。可以通过绘图等方式来展示聚类结果,以便进一步分析和评价。 5. 对聚类结果进行评价。评价指标通常包括SSE(误差平方和)、轮廓系数等。这些指标可以帮助我们判断聚类的效果如何。 下面通过一个简单的例子来演示K-means聚类算法实现。 假设我们有如下一组二维数据: data = [0.5 1.2; 0.3 1.0; 0.4 1.5; 1.4 2.0; 1.2 1.8; 1.3 2.5; 3.5 3.8; 3.0 4.2; 2.7 4.5; 3.2 3.5]; 我们需要将它们聚成三个簇。在Matlab中,我们可以这样实现: 1. 载入数据集。 2. 预处理数据集。这里我们不需要进行任何操作,因为数据点已经在同一尺度下,并且没有缺失值。 3. 调用kmeans函数。我们设置K=3,最大迭代次数为100次。初始聚类中心默认是随机生成的。 [idx,centroids,sumd] = kmeans(data,3,'MaxIter',100); 4. 获取聚类结果。idx为每个数据点所属的簇编号,centroids为每个簇的中心点坐标,sumd为SSE值。 5. 对聚类结果进行评价。这里我们使用轮廓系数作为评价指标。轮廓系数越大,表示聚类效果越好。 [s,h] = silhouette(data,idx); 最终的聚类结果和轮廓系数如下图所示: ![K-means聚类算法matlab实现图示](https://i.imgur.com/6sd97v0.png) 可以看到,聚类效果比较好,各个簇之间距离比较大,簇内距离比较小。轮廓系数为0.92,非常接近1,说明聚类效果很好。 总的来说,K-means聚类算法Matlab中是一个非常简单实现,只需要几行代码就能实现。然而,在实际应用中,选择合适的K值和评价指标,以及对数据进行预处理等步骤,这些都会影响聚类效果。因此,Matlab提供了丰富的工具和函数来帮助我们实现高质量的聚类分析。 ### 回答3: k-means聚类算法是一种经典的无监督学习算法,常用于将一组数据分成k个类别。在matlab实现k-means聚类算法有多种方式,可以使用自带的函数kmeans,也可以手动编写代码实现。 一、使用matlab自带函数kmeans 1.1 函数介绍 kmeans函数是matlab自带的实现k-means聚类算法的函数。它的具体使用方法如下: [idx, C] = kmeans(X, k) 其中,X是数据集,k是需要聚类的类别数,idx是每个样本所属的类别编号,C是每个类别的中心点。 1.2 使用方法 使用kmeans函数对数据进行聚类的具体步骤如下: (1)准备数据 需要将需要聚类的数据保存在矩阵X中。 (2)确定聚类数目 需要确定需要聚类的类别数目k。一般可以通过观察数据以及领域知识来确定。 (3)调用kmeans函数进行聚类 调用kmeans函数进行聚类,即输入数据矩阵X和聚类数目k,函数会输出每个样本所属的类别编号idx以及每个类别的中心点C。 (4)可视化 使用matlab的图形工具对数据进行可视化,便于观察聚类效果。 二、手动编写代码实现 2.1 实现思路 手动编写代码实现k-means聚类算法的基本思路如下: (1)随机选择k个点作为聚类中心。 (2)将每个样本点分配给距离最近的聚类中心。 (3)更新每个聚类的中心点。 (4)重复步骤(2)和(3),直到聚类结果不再改变。 2.2 算法流程 实现k-means聚类算法的具体流程如下: (1)随机选择k个点作为聚类中心。 (2)计算每个样本点与每个聚类中心的距离,找到距离最近的聚类中心,并将样本点分配给该聚类。 (3)按照每个聚类中的样本点重新计算聚类中心。 (4)重复步骤(2)和(3),直到聚类结果不再改变。 2.3 实现代码 可以通过以下代码实现k-means聚类算法: function [idx, C] = My_KMeans(X, k) % Input: % X: 数据集,每行代表一个样本; % k: 聚类数目; % % Output: % idx: 每个样本点所属的聚类编号; % C: 每个聚类的中心点。 [m, n] = size(X); % 随机选择k个点作为聚类中心 C = X(randperm(m, k), :); % 初始化idx idx = zeros(m, 1); % 计算每个样本点与每个聚类中心的距离 D = pdist2(X, C); % 迭代聚类过程 while true % 找到每个样本点距离最近的聚类中心 [d, new_idx] = min(D, [], 2); % 判断聚类结果是否满足终止条件 if new_idx == idx break; end idx = new_idx; % 更新每个聚类的中心点 for i = 1:k sel = (idx == i); C(i, :) = mean(X(sel, :), 1); end D = pdist2(X, C); end end 参考资料: [1] https://ww2.mathworks.cn/help/stats/kmeans.html [2] https://blog.csdn.net/u014793102/article/details/68472074 [3] https://blog.csdn.net/qq_40435156/article/details/82649045

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值