基于Matlab的PCA后GMM聚类与阈值确定毕设技术求助
针对你的PCA后数据重叠问题,用GMM做故障检测的Matlab实现方案
嘿,你的毕设遇到的这个问题很典型——PCA降维后健康和故障数据重叠,说明线性降维的区分度不够,用GMM这种概率模型来建模健康数据的分布,确实是个不错的思路。下面我一步步给你讲具体操作,附带Matlab代码,你可以直接套用到你的数据上:
1. 先把数据理清楚,完成PCA投影
首先要确保你的数据格式是每行一个样本,每列一个变量。假设你的健康数据存在X_healthy(比如m行9列),7组故障数据存在一个细胞数组X_fault里(X_fault{1}到X_fault{7}分别对应每组故障数据)。
关键:PCA必须只用健康数据训练,这样才能保证投影空间是基于健康状态的:
% 对健康数据做PCA,提取前3个主成分 [coeff, score_healthy, ~] = pca(X_healthy); PC_num = 3; coeff_selected = coeff(:, 1:PC_num); % 把健康数据投影到PCA空间 score_healthy_pca = score_healthy(:, 1:PC_num); % 把所有故障数据也投影到同一个PCA空间 score_fault_pca = []; for i = 1:7 % 注意要减去健康数据的均值,和PCA训练时保持一致 score_temp = (X_fault{i} - mean(X_healthy, 1)) * coeff_selected; score_fault_pca = [score_fault_pca; score_temp]; end % 合并所有数据方便后续处理 all_scores = [score_healthy_pca; score_fault_pca];
2. 用健康数据训练GMM模型
GMM的作用是拟合健康数据在PCA空间里的概率分布,后续我们用这个分布来判断样本是否“异常”。Matlab自带的fitgmdist函数可以直接用:
方法一:手动指定分量数
如果你想快速测试,可以先指定分量数(比如2-5,一般2或3就够):
k = 2; % 先试试2个分量 gmm_model = fitgmdist(score_healthy_pca, k);
方法二:用BIC准则自动选最优分量数
如果想更严谨,用贝叶斯信息准则(BIC)选最优的分量数,避免过拟合或欠拟合:
max_k = 5; % 最多试5个分量 bic_values = zeros(max_k, 1); for k = 1:max_k model = fitgmdist(score_healthy_pca, k); bic_values(k) = model.BIC; end % 找BIC最小的分量数(BIC越小,模型拟合越好) [~, optimal_k] = min(bic_values); gmm_model = fitgmdist(score_healthy_pca, optimal_k);
3. 计算每个样本的对数概率密度
训练好GMM后,计算每个样本在这个模型下的对数概率密度——健康样本的概率会比较高,故障样本因为偏离健康分布,概率会低很多:
% 健康样本的对数概率 log_prob_healthy = logpdf(gmm_model, score_healthy_pca); % 故障样本的对数概率 log_prob_fault = logpdf(gmm_model, score_fault_pca);
4. 确定故障检测的阈值
我们用健康样本的对数概率分布来设定阈值,比如取健康样本对数概率的第5百分位数——意思是95%的健康样本概率都高于这个值,低于这个值的样本就判定为故障:
% 计算第5百分位作为阈值(你也可以试试第10百分位,根据误报率调整) threshold = prctile(log_prob_healthy, 5);
如果想更精准,也可以画ROC曲线找最优阈值,但毕设里用百分位数已经足够直观,容易解释。
5. 验证检测效果并可视化
最后一步就是看看你的GMM模型能不能有效区分健康和故障数据:
% 计算健康样本的误报率(把健康判成故障的比例) healthy_pred = log_prob_healthy < threshold; false_alarm_rate = sum(healthy_pred)/length(healthy_pred); fprintf('健康样本误报率:%.2f%%\n', false_alarm_rate*100); % 计算故障样本的检测率(把故障正确判出来的比例) fault_pred = log_prob_fault < threshold; detection_rate = sum(fault_pred)/length(fault_pred); fprintf('故障样本检测率:%.2f%%\n', detection_rate*100); % 画箱线图直观对比 boxplot([log_prob_healthy; log_prob_fault], ... 'Labels', {'健康数据', '故障数据'}, ... 'Title', '健康与故障数据的对数概率分布'); hold on; % 画出阈值线 plot([1,2], [threshold, threshold], 'r--', 'LineWidth', 2); legend('样本数据', '检测阈值'); hold off;
几个关键提醒
- 绝对不能用故障数据训练GMM:GMM是用来建模健康状态的分布,混进故障数据会让模型“适应”异常,失去检测能力。
- 如果对数概率的区分度还是不够,可以试试用PCA的残差来训练GMM:就是原始数据减去PCA重构的数据,残差里的异常信号有时候更明显。
- 分量数k不用太大,一般2-3就足够,太大容易过拟合健康数据的噪声。
内容的提问来源于stack exchange,提问作者user624918
相关产品推荐
相关产品推荐

