1. 聚类算法概述与Matlab实现
聚类分析是数据挖掘和机器学习领域的重要技术手段,它能够将数据集中的对象分组,使得同一组(称为簇)内的对象彼此相似,而不同组之间的对象差异较大。在Matlab环境中,我们可以方便地实现多种经典聚类算法,包括K-means、模糊C-means、层次聚类、神经网络聚类和高斯混合模型等。这些算法各有特点,适用于不同类型的数据集和分析需求。
2. 五种主流聚类算法原理与实现
2.1 K-means聚类算法
K-means是最经典也是最常用的聚类算法之一,其核心思想是通过迭代将数据点划分到K个簇中,使得每个数据点都属于离它最近的均值(即聚类中心)对应的簇。
算法实现步骤:
- 随机选择K个数据点作为初始聚类中心
- 计算每个数据点到各聚类中心的距离,并将其分配到最近的簇
- 重新计算每个簇的均值作为新的聚类中心
- 重复步骤2-3,直到聚类中心不再变化或达到最大迭代次数
matlab复制% K-means聚类Matlab实现示例
data = rand(100,2); % 生成100个二维随机数据点
k = 3; % 设置聚类数量
[idx, centers] = kmeans(data, k);
% 可视化聚类结果
figure;
gscatter(data(:,1), data(:,2), idx);
hold on;
plot(centers(:,1), centers(:,2), 'kx', 'MarkerSize', 15, 'LineWidth', 3);
title('K-means聚类结果');
legend('Cluster 1', 'Cluster 2', 'Cluster 3', 'Centroids');
关键参数说明:
k:预设的聚类数量,需要根据数据特点或经验确定distance:距离度量方式,常用欧氏距离('sqeuclidean')或曼哈顿距离('cityblock')replicates:重复运行次数,避免局部最优解
提示:K-means对初始中心点敏感,建议设置较大的replicates值(如10-20),让算法多次运行选择最佳结果。
2.2 模糊C-means聚类算法
模糊C-means(FCM)是K-means的模糊扩展版本,允许数据点以不同的隶属度属于多个簇,更适合处理边界模糊的数据集。
算法特点:
- 引入隶属度矩阵,表示每个数据点对各簇的归属程度
- 使用模糊因子m控制聚类的模糊程度(m>1)
- 通过最小化目标函数迭代优化隶属度和聚类中心
matlab复制% 模糊C-means聚类Matlab实现
data = rand(100,2); % 测试数据
options = [2, 100, 1e-5, 0]; % [模糊因子m, 最大迭代次数, 收敛阈值, 显示信息]
[centers, U] = fcm(data, 3, options);
% 根据最大隶属度确定数据点所属簇
[~, idx] = max(U);
% 可视化结果
figure;
gscatter(data(:,1), data(:,2), idx);
hold on;
plot(centers(:,1), centers(:,2), 'kx', 'MarkerSize', 15, 'LineWidth', 3);
title('模糊C-means聚类结果');
参数选择建议:
- 模糊因子m通常取1.5-3.0,值越大聚类越模糊
- 收敛阈值一般设为1e-5到1e-6
- 最大迭代次数建议100-200次
2.3 层次聚类算法
层次聚类通过构建树状图(dendrogram)来展示数据的层次结构,不需要预先指定聚类数量。Matlab中提供了linkage和cluster函数实现层次聚类。
实现步骤:
- 计算数据点间的距离矩阵
- 使用linkage函数构建聚类树
- 通过cluster函数切割聚类树得到最终聚类结果
matlab复制% 层次聚类Matlab实现
data = rand(100,2); % 测试数据
dist = pdist(data); % 计算距离矩阵
tree = linkage(dist, 'average'); % 使用平均链接法构建聚类树
% 可视化树状图
figure;
dendrogram(tree);
title('层次聚类树状图');
% 切割树状图得到聚类结果
idx = cluster(tree, 'maxclust', 3); % 指定分为3类
% 可视化聚类结果
figure;
gscatter(data(:,1), data(:,2), idx);
title('层次聚类结果');
链接方法选择:
- 'single':单链接,计算簇间最近点距离
- 'complete':全链接,计算簇间最远点距离
- 'average':平均链接,计算簇间平均距离(常用)
- 'ward':Ward方法,最小化簇内方差
2.4 高斯混合模型聚类
高斯混合模型(GMM)假设数据由多个高斯分布混合生成,通过EM算法估计各高斯成分的参数,实现基于概率的软聚类。
Matlab实现:
matlab复制% 高斯混合模型聚类
data = randn(100,2); % 生成测试数据
data(1:50,:) = data(1:50,:) + 2; % 偏移部分数据
data(51:100,:) = data(51:100,:) - 2; % 偏移另一部分数据
gmm = fitgmdist(data, 2); % 拟合2成分GMM模型
idx = cluster(gmm, data); % 获取聚类结果
% 可视化聚类结果
figure;
gscatter(data(:,1), data(:,2), idx);
hold on;
ezcontour(@(x,y)pdf(gmm,[x y]), [-5 5], [-5 5]);
title('高斯混合模型聚类结果');
模型参数说明:
- 协方差矩阵类型:'full'(完全协方差)、'diagonal'(对角协方差)、'shared'(共享协方差)
- 正则化值:防止奇异协方差矩阵,通常设为1e-6
- 初始值设置:可以使用k-means结果作为初始值加速收敛
2.5 自组织映射神经网络聚类
自组织映射(SOM)是一种无监督神经网络,通过竞争学习将高维数据映射到低维(通常2D)网格上,实现聚类和可视化。
Matlab实现:
matlab复制% SOM神经网络聚类
data = rand(100,4); % 4维测试数据
net = selforgmap([5 5]); % 创建5x5的SOM网络
net = train(net, data'); % 训练网络
idx = vec2ind(net(data')); % 获取聚类结果
% 可视化结果
figure;
plotsomtop(net);
title('SOM神经元权重');
figure;
plotsomhits(net, data');
title('数据点在SOM上的分布');
网络参数调整:
- 网格大小:决定聚类数量,通常根据数据量选择
- 学习率:控制权重更新幅度,初始值0.1-0.3
- 邻域函数:常用高斯函数或气泡函数
- 训练次数:通常100-1000次迭代
3. 聚类算法评估与比较
3.1 内部评估指标
内部评估指标仅基于数据本身评估聚类质量,无需外部标签信息。
常见内部指标:
- 轮廓系数(Silhouette Coefficient)
matlab复制silhouette(data, idx); % 计算并绘制轮廓系数 - 戴维森堡丁指数(Davies-Bouldin Index)
matlab复制eval = evalclusters(data, idx, 'DaviesBouldin'); - 簇内平方和(Within-cluster sum of squares)
matlab复制sumd = kmeans(data, k, 'Distance', 'sqeuclidean');
3.2 外部评估指标
当有真实标签时,可以使用外部指标评估聚类结果与真实分类的一致性。
常用外部指标:
- 调整兰德指数(Adjusted Rand Index)
matlab复制ari = rand_index(true_labels, idx, 'adjusted'); - 互信息(Mutual Information)
matlab复制mi = mutual_info(true_labels, idx); - 同质性(Homogeneity)和完整性(Completeness)
matlab复制[h, c] = homogeneity_completeness(true_labels, idx);
3.3 算法性能比较
下表对比了五种聚类算法的主要特点和适用场景:
| 算法 | 需要预设K | 聚类形状 | 计算复杂度 | 适用场景 |
|---|---|---|---|---|
| K-means | 是 | 球形 | O(nkt) | 大数据集,快速聚类 |
| 模糊C-means | 是 | 球形 | O(nkt) | 边界模糊的数据 |
| 层次聚类 | 否 | 任意 | O(n²) | 小数据集,需要层次结构 |
| GMM | 是 | 椭圆 | O(nkt) | 概率模型,异常检测 |
| SOM | 是(网格) | 拓扑保持 | O(n) | 高维数据可视化 |
4. 聚类算法应用实例
4.1 客户细分分析
matlab复制% 加载客户数据
load customer_data.mat % 包含年龄、收入、消费频率等特征
% 数据标准化
data = zscore(customer_data);
% 使用K-means聚类
k = 4;
[idx, centers] = kmeans(data, k, 'Replicates', 10);
% 分析聚类中心
cluster_profiles = array2table(centers, 'VariableNames', {'Age','Income','Frequency'},...
'RowNames', {'Cluster1','Cluster2','Cluster3','Cluster4'});
disp(cluster_profiles);
% 可视化
figure;
parallelcoords(data, 'Group', idx);
title('客户聚类平行坐标图');
4.2 图像颜色量化
matlab复制% 读取图像
img = imread('peppers.png');
img_data = double(reshape(img, [], 3)); % 将图像展开为RGB向量
% 使用K-means进行颜色量化
k = 8; % 量化到8种颜色
[idx, centers] = kmeans(img_data, k);
% 重建量化后的图像
quantized_img = reshape(centers(idx,:), size(img));
% 显示结果
figure;
subplot(1,2,1); imshow(img); title('原始图像');
subplot(1,2,2); imshow(uint8(quantized_img)); title(['颜色量化(k=' num2str(k) ')']);
4.3 异常检测应用
matlab复制% 生成包含异常值的数据
data = [randn(100,2); rand(5,2)*10-5];
% 使用GMM进行异常检测
gmm = fitgmdist(data, 1, 'Replicates', 5);
pdf_values = pdf(gmm, data);
threshold = quantile(pdf_values, 0.05); % 取概率密度最低的5%作为异常值
outliers = pdf_values < threshold;
% 可视化
figure;
gscatter(data(:,1), data(:,2), outliers, 'br', '..', [15 15]);
title('基于GMM的异常检测');
legend('正常点', '异常点');
5. 聚类算法优化与改进
5.1 K-means++初始化
K-means++改进了初始中心点的选择,能有效避免算法陷入局部最优。
matlab复制% K-means++初始化实现
function centers = kmeanspp_init(data, k)
centers = zeros(k, size(data,2));
centers(1,:) = data(randi(size(data,1)),:); % 随机选择第一个中心
for i = 2:k
% 计算每个点到最近中心的距离平方
dist = pdist2(data, centers(1:i-1,:)).^2;
min_dist = min(dist, [], 2);
% 按距离平方的概率选择下一个中心
prob = min_dist / sum(min_dist);
centers(i,:) = data(find(rand < cumsum(prob), 1), :);
end
end
% 使用K-means++初始化
data = rand(1000,2);
k = 5;
init_centers = kmeanspp_init(data, k);
[idx, centers] = kmeans(data, k, 'Start', init_centers);
5.2 自适应确定聚类数量
通过肘部法则或轮廓系数自动确定最佳K值。
matlab复制% 肘部法则确定最佳K值
data = rand(500,3);
max_k = 10;
wss = zeros(max_k,1);
for k = 1:max_k
[~, ~, sumd] = kmeans(data, k);
wss(k) = sum(sumd);
end
% 绘制肘部曲线
figure;
plot(1:max_k, wss, 'bo-');
xlabel('聚类数量K');
ylabel('簇内平方和');
title('肘部法则确定最佳K值');
5.3 处理非球形簇的谱聚类
谱聚类能有效处理非球形分布的数据。
matlab复制% 谱聚类实现
data = [randn(100,2); randn(100,2)+[3,0]; randn(100,2)+[1.5,2.6]];
% 构建相似度矩阵
sigma = 0.5;
W = exp(-pdist2(data,data).^2/(2*sigma^2));
D = diag(sum(W,2));
L = D - W; % 非规范化拉普拉斯矩阵
% 计算前k个特征向量
k = 3;
[eig_vecs, ~] = eigs(L, D, k, 'smallestreal');
% 对特征向量进行K-means聚类
idx = kmeans(eig_vecs, k);
% 可视化结果
figure;
gscatter(data(:,1), data(:,2), idx);
title('谱聚类结果');
6. 聚类算法常见问题与解决方案
6.1 数据预处理问题
问题: 不同量纲的特征导致聚类结果偏向大数值特征。
解决方案: 标准化处理
matlab复制% Z-score标准化
data = zscore(raw_data);
% 最大最小归一化
data = (raw_data - min(raw_data)) ./ (max(raw_data) - min(raw_data));
6.2 高维数据聚类问题
问题: 高维数据中距离度量失效(维度灾难)。
解决方案1: 特征选择
matlab复制% 使用PCA降维
[coeff, score, latent] = pca(data);
explained = cumsum(latent)./sum(latent);
k = find(explained >= 0.95, 1); % 保留95%方差
reduced_data = score(:,1:k);
解决方案2: 使用适合高维数据的算法(如谱聚类或子空间聚类)
6.3 非均衡簇问题
问题: 簇大小差异大时,小簇容易被大簇吞并。
解决方案1: 使用加权K-means
matlab复制% 为每个数据点分配权重
weights = compute_weights(data); % 自定义权重计算函数
[idx, centers] = weighted_kmeans(data, k, weights);
解决方案2: 使用密度聚类算法(如DBSCAN)
6.4 算法收敛问题
问题: 算法不收敛或收敛到局部最优。
解决方案1: 增加重复次数
matlab复制[idx, centers] = kmeans(data, k, 'Replicates', 20);
解决方案2: 使用改进的初始化方法(如K-means++)
解决方案3: 调整算法参数
matlab复制% 模糊C-means参数调整
options = [2.5, 200, 1e-6, 1]; % [m, max_iter, tol, display]
[centers, U] = fcm(data, k, options);
7. 高级聚类技术与扩展应用
7.1 时间序列聚类
matlab复制% 动态时间规整(DTW)距离计算
function dist = dtw_distance(x, y)
n = length(x);
m = length(y);
dtw_mat = zeros(n+1, m+1);
dtw_mat(:,:) = inf;
dtw_mat(1,1) = 0;
for i = 2:n+1
for j = 2:m+1
cost = abs(x(i-1) - y(j-1));
dtw_mat(i,j) = cost + min([dtw_mat(i-1,j), dtw_mat(i,j-1), dtw_mat(i-1,j-1)]);
end
end
dist = dtw_mat(n+1,m+1);
end
% 时间序列聚类示例
load ecg_data.mat; % 加载ECG时间序列数据
n = size(ecg_data,1);
dist_mat = zeros(n,n);
% 计算DTW距离矩阵
for i = 1:n
for j = i+1:n
dist_mat(i,j) = dtw_distance(ecg_data(i,:), ecg_data(j,:));
dist_mat(j,i) = dist_mat(i,j);
end
end
% 层次聚类
tree = linkage(squareform(dist_mat), 'average');
idx = cluster(tree, 'maxclust', 3);
7.2 多视图聚类
matlab复制% 多视图数据聚类示例
view1 = rand(100,10); % 第一视图数据
view2 = rand(100,15); % 第二视图数据
% 分别计算相似度矩阵
W1 = exp(-pdist2(view1,view1).^2);
W2 = exp(-pdist2(view2,view2).^2);
% 多视图融合
alpha = 0.5; % 视图权重
W_combined = alpha*W1 + (1-alpha)*W2;
% 谱聚类
D = diag(sum(W_combined,2));
L = D - W_combined;
[eig_vecs, ~] = eigs(L, D, 3, 'smallestreal');
idx = kmeans(eig_vecs, 3);
7.3 半监督聚类
matlab复制% 半监督K-means实现
data = rand(100,2);
k = 3;
% 已知部分标签(0表示未知)
labels = zeros(100,1);
labels(1:10) = 1; % 前10个样本属于类别1
labels(91:100) = 3; % 最后10个样本属于类别3
% 初始化中心点
known_data = data(labels~=0,:);
known_labels = labels(labels~=0);
init_centers = zeros(k, size(data,2));
for i = 1:k
init_centers(i,:) = mean(known_data(known_labels==i,:), 1);
end
% 运行半监督K-means
[idx, centers] = kmeans(data, k, 'Start', init_centers);
8. 聚类结果可视化技巧
8.1 高维数据可视化
matlab复制% t-SNE降维可视化
data = rand(200,10); % 10维数据
labels = kmeans(data, 4);
% t-SNE降维到2D
Y = tsne(data);
figure;
gscatter(Y(:,1), Y(:,2), labels);
title('t-SNE可视化聚类结果');
8.2 聚类边界可视化
matlab复制% 绘制K-means聚类边界
data = rand(200,2);
k = 3;
[idx, centers] = kmeans(data, k);
% 生成网格点
[x_grid, y_grid] = meshgrid(0:0.01:1, 0:0.01:1);
grid_points = [x_grid(:), y_grid(:)];
% 预测网格点类别
grid_idx = kmeans_predict(grid_points, centers);
% 绘制决策边界
figure;
gscatter(data(:,1), data(:,2), idx);
hold on;
contour(x_grid, y_grid, reshape(grid_idx, size(x_grid)), 1:k, 'LineWidth', 2);
plot(centers(:,1), centers(:,2), 'kx', 'MarkerSize', 15, 'LineWidth', 3);
title('K-means聚类边界');
8.3 热图可视化
matlab复制% 聚类热图
data = randn(50,20); % 50个样本,20个特征
idx = kmeans(data, 4);
% 按聚类结果排序
[~, sort_idx] = sort(idx);
sorted_data = data(sort_idx,:);
% 绘制热图
figure;
imagesc(sorted_data);
colormap(jet);
colorbar;
title('聚类热图');
xlabel('特征');
ylabel('样本(按聚类排序)');
9. 实际应用中的经验分享
9.1 特征工程技巧
-
相关性分析: 聚类前应检查特征间的相关性,避免冗余特征影响聚类效果。
matlab复制
corr_matrix = corr(data); heatmap(corr_matrix); -
非线性变换: 对偏态分布的特征进行对数或Box-Cox变换。
matlab复制data(:,3) = log1p(data(:,3)); % 对数变换 -
特征组合: 创建有意义的衍生特征可能提升聚类效果。
matlab复制data(:,end+1) = data(:,1)./data(:,2); % 创建比率特征
9.2 算法选择建议
- 数据量小于1万: 可以尝试层次聚类或谱聚类
- 数据量1万-10万: K-means或GMM是较好选择
- 数据量大于10万: 使用Mini-Batch K-means
matlab复制opts = statset('UseParallel', true); [idx, centers] = kmeans(data, k, 'Options', opts, 'MaxIter', 100, ... 'OnlinePhase', 'on', 'Display', 'iter');
9.3 性能优化技巧
-
并行计算: 利用Matlab并行计算工具箱加速
matlab复制parpool(4); % 开启4个工作进程 options = statset('UseParallel', true); [idx, centers] = kmeans(data, k, 'Options', options); -
内存优化: 对于超大矩阵,使用单精度或稀疏矩阵
matlab复制data = single(data); % 转换为单精度节省内存 -
增量计算: 对无法一次性加载的大数据,使用增量聚类
matlab复制% 分批加载数据并更新模型 gmm = fitgmdist(first_batch, k); for i = 2:num_batches gmm = gmdistribution.fit(gmm, next_batch, 'Options', options); end
10. 聚类项目完整案例
10.1 电商用户行为分析
matlab复制% 加载和预处理数据
user_data = readtable('user_behavior.csv');
features = user_data{:, {'visit_freq', 'purchase_amount', 'dwell_time'}};
features = zscore(features); % 标准化
% 确定最佳K值
eva = evalclusters(features, 'kmeans', 'silhouette', 'KList', 1:8);
k = eva.OptimalK;
% 聚类分析
[idx, centers] = kmeans(features, k, 'Replicates', 10);
% 分析聚类特征
cluster_stats = grpstats(features, idx, {'mean', 'std'});
disp(cluster_stats);
% 可视化
parallelcoords(features, 'Group', idx, 'Quantile', 0.25);
title('用户分群特征平行坐标图');
10.2 基因表达数据分析
matlab复制% 加载基因表达数据
load gene_expression.mat; % 包含1000个基因在200个样本中的表达量
% 过滤低方差基因
gene_var = var(gene_data, 0, 2);
filtered_data = gene_data(gene_var > quantile(gene_var, 0.8), :);
% 层次聚类
corr_dist = pdist(1 - corr(filtered_data'));
gene_tree = linkage(corr_dist, 'average');
% 绘制热图聚类
figure;
dendrogram(gene_tree, 0);
title('基因聚类树状图');
% 样本聚类
sample_dist = pdist(filtered_data');
sample_tree = linkage(sample_dist, 'ward');
figure;
[h, ~, perm] = dendrogram(sample_tree, 0);
title('样本聚类树状图');
% 热图展示
figure;
imagesc(filtered_data(:,perm));
colormap(jet);
colorbar;
title('基因表达热图(按样本聚类排序)');
10.3 图像分割应用
matlab复制% 图像聚类分割
img = imread('peppers.png');
img_data = double(reshape(img, [], 3)); % 展开为RGB向量
% 添加空间信息
[x,y] = meshgrid(1:size(img,2), 1:size(img,1));
spatial_data = [x(:), y(:)] / max(size(img)); % 归一化坐标
features = [img_data, spatial_data]; % 结合颜色和空间特征
% 模糊C-means聚类
options = [2, 100, 1e-5, 0];
[centers, U] = fcm(features, 4, options);
% 获取分割结果
[~, idx] = max(U, [], 2);
segmented_img = reshape(centers(idx,1:3), size(img));
% 显示结果
figure;
subplot(1,2,1); imshow(img); title('原始图像');
subplot(1,2,2); imshow(uint8(segmented_img)); title('聚类分割结果');