Kmeans聚类算法原理与Matlab实战指南
2026/9/13 10:56:35 网站建设 项目流程

1. Kmeans聚类算法基础与Matlab实现

Kmeans算法是一种经典的基于距离的无监督学习算法,它通过迭代将数据点分配到最近的聚类中心,然后重新计算聚类中心,直到满足收敛条件。在Matlab中,kmeans函数的基本语法如下:

[idx, C] = kmeans(X, k)

其中X是n×p的数据矩阵(n个样本,p个特征),k是指定的聚类数目,idx是包含每个样本所属聚类索引的n×1向量,C是k×p的矩阵,包含k个聚类中心的位置。

实际应用中,建议先对数据进行标准化处理(z-score标准化或min-max标准化),避免不同量纲的特征对距离计算产生不均衡影响。

Matlab的kmeans函数默认使用k-means++算法进行初始化,这比随机初始化能获得更好的聚类结果。k-means++通过以下步骤选择初始聚类中心:

  1. 随机选择第一个中心点
  2. 计算每个点到最近中心的距离D(x)
  3. 按照D(x)²的概率选择下一个中心点
  4. 重复步骤2-3直到选出k个中心

2. 肘部法确定最佳聚类数

2.1 肘部法原理

肘部法(Elbow Method)通过观察不同k值下聚类误差的变化趋势来确定最佳聚类数。聚类误差通常用所有样本到其所属聚类中心的距离平方和(SSE)来衡量:

[~, ~, sumd] = kmeans(X, k); SSE = sum(sumd);

随着k增大,SSE会逐渐减小,当k增加到真实聚类数时,SSE的下降幅度会突然变缓,这个转折点就是"肘部点"。

2.2 Matlab实现肘部法

% 生成测试数据 rng(1); % 设置随机种子保证可重复性 X = [randn(100,2)*0.75+ones(100,2); randn(100,2)*0.5-ones(100,2)]; % 尝试不同的k值 k_range = 1:8; SSE = zeros(size(k_range)); for i = 1:length(k_range) [~, ~, sumd] = kmeans(X, k_range(i), 'Replicates', 5); SSE(i) = sum(sumd); end % 绘制肘部曲线 figure; plot(k_range, SSE, 'bo-'); xlabel('聚类数目 k'); ylabel('SSE'); title('肘部法确定最佳聚类数'); grid on;

2.3 结果分析与选择

在实际分析肘部曲线时,应该寻找SSE下降速度明显变缓的点。例如,如果曲线在k=2或k=3处出现明显拐点,那么这两个值都可能是合理的聚类数选择。此时可以结合业务需求和其他评估指标(如轮廓系数)进行综合判断。

3. 高级应用与参数调优

3.1 距离度量选择

Matlab的kmeans函数支持多种距离度量方式,通过'Distance'参数指定:

  • 'sqeuclidean':平方欧氏距离(默认)
  • 'cityblock':曼哈顿距离
  • 'cosine':余弦距离
  • 'correlation':相关系数距离
  • 'hamming':汉明距离(仅适用于二进制数据)
% 使用余弦距离进行聚类 [idx, C] = kmeans(X, 3, 'Distance', 'cosine');

3.2 并行计算加速

对于大型数据集,可以使用并行计算加速kmeans:

options = statset('UseParallel', 1); [idx, C] = kmeans(X, 3, 'Options', options);

3.3 多次重复与初始点选择

为避免局部最优,可以设置'Replicates'参数多次运行算法并选择最佳结果:

[idx, C, sumd] = kmeans(X, 3, 'Replicates', 10, 'Display', 'final');

4. 实战案例:鸢尾花数据集聚类

4.1 数据准备与可视化

load fisheriris; X = meas(:,3:4); % 使用花瓣长度和宽度作为特征 figure; gscatter(X(:,1), X(:,2), species); title('鸢尾花真实类别'); xlabel('花瓣长度 (cm)'); ylabel('花瓣宽度 (cm)');

4.2 应用肘部法确定k值

k_range = 1:5; SSE = zeros(size(k_range)); for i = 1:length(k_range) [~, ~, sumd] = kmeans(X, k_range(i), 'Replicates', 5); SSE(i) = sum(sumd); end figure; plot(k_range, SSE, 'bo-'); xlabel('聚类数目 k'); ylabel('SSE'); title('鸢尾花数据肘部曲线');

4.3 最终聚类与评估

k = 3; % 根据肘部法选择 [idx, C] = kmeans(X, k, 'Replicates', 10); % 可视化聚类结果 figure; gscatter(X(:,1), X(:,2), idx, 'rgb', 'osd'); hold on; plot(C(:,1), C(:,2), 'kx', 'MarkerSize', 15, 'LineWidth', 3); legend('Cluster 1', 'Cluster 2', 'Cluster 3', 'Centroids'); title('Kmeans聚类结果'); xlabel('花瓣长度 (cm)'); ylabel('花瓣宽度 (cm)');

5. 常见问题与解决方案

5.1 空聚类处理

当某个聚类失去所有成员时,kmeans提供三种处理方式:

  • 'error':报错(默认)
  • 'drop':删除空聚类
  • 'singleton':创建一个新聚类(包含离当前中心最远的点)
[idx, C] = kmeans(X, k, 'EmptyAction', 'singleton');

5.2 收敛问题

如果算法不收敛,可以尝试:

  1. 增加最大迭代次数
  2. 调整收敛容差
  3. 使用不同的初始点策略
options = statset('MaxIter', 1000, 'TolFun', 1e-6); [idx, C] = kmeans(X, k, 'Options', options);

5.3 高维数据聚类

对于高维数据,建议:

  1. 先进行PCA降维
  2. 使用更适合高维数据的距离度量(如余弦距离)
  3. 增加聚类重复次数
[coeff, score] = pca(X); X_reduced = score(:,1:2); % 保留前两个主成分 [idx, C] = kmeans(X_reduced, k);

在实际项目中,我发现将肘部法与轮廓系数结合使用能获得更可靠的聚类数估计。同时,对于不同量纲的特征,标准化处理是必不可少的步骤,否则距离计算会被量纲较大的特征主导。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询