文章目录
- 为什么要检测异常值
- 方法一:四分位距法(IQR)
- 方法二:3σ 准则
- 方法三:基于密度检测
- 方法四:孤立森林
- 方法五:聚类方法
- 单变量 vs 多变量
- 找到异常值怎么办
- 小结
做数据分析第一步往往就是异常值检测,不正常的点不找出来会把整个模型带偏。Matlab 里做异常值检测有好几种方法,本文整理常用的,代码直接就能用。
为什么要检测异常值
异常值可能来自测量错误、记录错误,也可能就是真的稀有事件。不管来源,不处理的话:
- 拟合曲线会偏
- 统计量均值方差不准
- 模型训练容易过拟合
所以拿到数据先扫一遍有没有异常值,处理完再往下分析。
方法一:四分位距法(IQR)
最简单常用,不假设数据分布,鲁棒性好。
原理:
- 排好序,找 25% 分位数 Q1 和 75% 分位数 Q3
- IQR = Q3 - Q1
- 异常值判定:小于 Q1 - 1.5×IQR 或者大于 Q3 + 1.5×IQR
代码实现:
functionoutlier_idx=iqr_detect(data)% IQR_DETECT 四分位距法检测异常值% outlier_idx = iqr_detect(data) 返回逻辑索引,true是异常值Q1=quantile(data,0.25);Q3=quantile(data,0.75);IQR=Q3-Q1;lower=Q1-1.5*IQR;upper=Q3+1.5*IQR;outlier_idx=data<lower|data>upper;end用法:
data=[normrnd(0,1,1,100),10,-8];% 加两个异常值idx=iqr_detect(data);fprintf('检测到%d个异常值\n',sum(idx));clean_data=data(~idx);% 去掉异常值箱线图直接帮你标出来:
figure;boxplot(data);红加号就是异常值,一眼看出来。
方法二:3σ 准则
假设数据服从正态分布,偏离均值三倍标准差就算异常值。
代码:
functionoutlier_idx=three_sigma_detect(data)mu=mean(data);sigma=std(data);outlier_idx=abs(data-mu)>3*sigma;end这个方法简单,数据真的近似正态分布效果很好。数据偏态或者有多个峰效果就差了。
方法三:基于密度检测
局部离群因子算法 LOF,比较每个点局部密度,密度远低于邻居就是异常值。Matlab 统计工具箱有lofd函数:
% R2021a以后支持[scores,labels]=lof(X,5);% 5个邻居outlier_idx=scores>1.5;% 分数越大越可能异常X 是 n×d 数据矩阵,每行一个样本,高维数据也能用。
方法四:孤立森林
孤立森林适合高维数据,速度快。统计机器学习工具箱自带:
iforest=IsolationForest;[~,scores]=iforest.fitPredict(X);outlier_idx=scores>0.7;% 得分越高越异常分数范围 0 到 1,一般 0.6-0.7 当阈值,自己调。
方法五:聚类方法
kmeans 聚类之后,每个点到最近聚类中心距离太大就是异常:
[idx,centers]=kmeans(X,k);d=zeros(size(X,1),1);fori=1:size(X,1)d(i)=norm(X(i,:)-centers(idx(i),:));end% 距离超过三倍标准差算异常outlier_idx=d>mean(d)+3*std(d);本来就要聚类,顺便找异常,一举两得。
单变量 vs 多变量
- 单变量:IQR 或者 3σ,简单快,足够用
- 多变量高维:孤立森林、LOF,效果更好
大部分情况你就分析一两个变量,IQR 足够,代码三行搞定。
找到异常值怎么办
几种处理方式:
- 数据量够,异常少:直接删掉
- 不能删:用中位数或者均值替换,推荐中位数,鲁棒
- 时序数据:插值填充,保持连续性
- 异常本身就是要找的:保留,单独分析
别上来就删,先看看为什么异常,是真错了还是本来就有极端值。有些问题就是要找异常,比如 fraud 检测,异常才是目标。
小结
- 单变量:优先 IQR,不假设分布,稳定
- 正态分布数据:3σ 简单直接
- 多变量高维:孤立森林
- 可视化:boxplot 一眼看出来
异常值检测不难,选对方法,代码直接套,检测完再处理,后面分析结果才可靠。