基于MATLAB的散点图正偏差异常值检测及曲线拟合需求
基于LOESS/LOWESS的自适应密度异常值检测方案(MATLAB实现)
核心思路
用LOESS拟合数据主趋势曲线,结合局部密度加权的置信区间作为异常判定边界,重点识别高于趋势线的正偏差点,负偏差点仅做标记不重点关注。这种方法既保证主数据簇的拟合准确率,又能根据数据密度动态调整检测灵敏度,适配不同分布的散点图。
MATLAB实现步骤
1. 数据预处理与LOESS趋势拟合
先对x轴数据排序(LOESS对有序数据拟合效果更稳定),用MATLAB内置工具生成趋势线及基础置信区间:
% 假设输入为x、y向量,先按x排序 [sortedX, idx] = sort(x); sortedY = y(idx); % 带置信区间的LOESS拟合,Span控制平滑度(0.1-1之间调整) mdl = fitlm(sortedX, sortedY, 'LinearModel', 'loess', 'Span', 0.3); pred = predict(mdl, sortedX); % 趋势预测值
Span参数:数据密集区可设较小值(贴近局部趋势),稀疏区设较大值(避免过度拟合噪声),也可通过交叉验证自动选最优值。
2. 生成随密度变化的自适应边界
默认置信区间是全局统一的,结合局部核密度估计调整边界宽度,实现密度越高、边界越严格的效果:
% 计算每个x点的局部密度 kde = fitdist(sortedX, 'Kernel', 'epanechnikov'); density = pdf(kde, sortedX); % 归一化密度值,避免极端值干扰边界调整 normDensity = (density - min(density))/(max(density)-min(density))*0.9 + 0.1; % 提取原始观测置信区间,用密度加权调整 [~,~,lower,upper] = predict(mdl, sortedX, 'Prediction', 'observation'); % 正偏差重点:密度越高,上边界越窄(严格检测) adjustedUpper = pred + (upper - pred)./normDensity; % 负偏差非重点:适度放宽下边界 adjustedLower = pred - (pred - lower)*normDensity;
3. 异常点标记与可视化验证
对比原始数据与自适应边界,标记异常点并还原到原始数据索引:
% 标记正/负偏差异常点 positiveOutliers = sortedY > adjustedUpper; negativeOutliers = sortedY < adjustedLower; % 还原原始数据的异常点索引 originalPosOutliers = false(size(x)); originalPosOutliers(idx(positiveOutliers)) = true; originalNegOutliers = false(size(x)); originalNegOutliers(idx(negativeOutliers)) = true; % 可视化确认 figure; scatter(x, y, 'b'); hold on; plot(sortedX, pred, 'r', 'LineWidth', 2); plot(sortedX, adjustedUpper, 'g--', 'LineWidth', 1.5); plot(sortedX, adjustedLower, 'm--', 'LineWidth', 1.5); scatter(x(originalPosOutliers), y(originalPosOutliers), 100, 'k', 'filled', 'MarkerEdgeColor', 'r'); scatter(x(originalNegOutliers), y(originalNegOutliers), 80, 'k', 'filled', 'MarkerEdgeColor', 'y'); legend('原始数据','LOESS趋势线','自适应上边界','自适应下边界','正偏差异常','负偏差异常');
关键调优策略
- Span参数优化:遍历0.2-0.8的取值,计算拟合残差的均方根,选择残差最小的Span值。
- 核密度带宽调整:若默认带宽不合适,手动设置
fitdist的Bandwidth参数,带宽越小密度检测越敏感。 - 置信区间类型切换:如需更保守的检测,用
'Prediction', 'confidence'(置信区间)替代观测区间,边界更窄。
批量处理适配
将逻辑封装为函数,循环处理数千个数据集:
function [posOutliers, negOutliers] = detectLOESSOutliers(x, y, span) % 实现上述预处理、拟合、边界调整、标记逻辑 [sortedX, idx] = sort(x); sortedY = y(idx); mdl = fitlm(sortedX, sortedY, 'LinearModel', 'loess', 'Span', span); pred = predict(mdl, sortedX); kde = fitdist(sortedX, 'Kernel', 'epanechnikov'); density = pdf(kde, sortedX); normDensity = (density - min(density))/(max(density)-min(density))*0.9 + 0.1; [~,~,lower,upper] = predict(mdl, sortedX, 'Prediction', 'observation'); adjustedUpper = pred + (upper - pred)./normDensity; adjustedLower = pred - (pred - lower)*normDensity; positiveOutliers = sortedY > adjustedUpper; negativeOutliers = sortedY < adjustedLower; posOutliers = false(size(x)); posOutliers(idx(positiveOutliers)) = true; negOutliers = false(size(x)); negOutliers(idx(negativeOutliers)) = true; end % 批量处理示例 for i = 1:numDatasets x = datasetList{i}.x; y = datasetList{i}.y; [pos, neg] = detectLOESSOutliers(x, y, 0.3); % 保存结果或自动生成报告 end
注意事项
- 若数据存在多簇分布,先通过
kmeans聚类,对每个簇单独做LOESS拟合,避免跨簇拟合导致的边界偏差。 - 对于x轴无明确顺序的散点,可按局部密度或y值排序后再拟合,保证LOESS的局部性效果。
内容的提问来源于stack exchange,提问作者S_Av
相关产品推荐
相关产品推荐

