You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

聚类离群点检测:含错误标注2D坐标点数据集的离群点过滤方法咨询

这问题我太熟了——z-score这类依赖全局均值、标准差的方法,完全不适配你这种**同时存在「聚集簇」和「分散簇」**的场景!全局统计量会被两种模式拉偏,导致大量正常的分散点被误判成离群。给你几个针对性的解决方案,都是我处理类似点云标注数据时亲测有效的:

1. 优先用DBSCAN(密度聚类)

DBSCAN的核心是「基于密度识别簇」,不管你的点是紧凑聚集还是稀疏分散,只要同属一个密度区域,就能被归为一类;完全孤立的离群点会被标记为噪声。完美匹配你的需求。

代码示例(针对单个样本的10-20个2D点):

from sklearn.cluster import DBSCAN
import numpy as np

def filter_outliers_dbscan(points, eps=None, min_samples=2):
    # points shape: (N, 2), N∈[10,20]
    if eps is None:
        # 自动计算eps:取每个点到第3个最近邻距离的90分位数,适配不同样本密度
        from sklearn.neighbors import NearestNeighbors
        nn = NearestNeighbors(n_neighbors=3).fit(points)
        distances, _ = nn.kneighbors(points)
        eps = np.quantile(distances[:, -1], 0.9)
    
    db = DBSCAN(eps=eps, min_samples=min_samples).fit(points)
    # labels=-1的就是离群点,返回布尔数组标记有效点
    return db.labels_ != -1
  • 关键参数:min_samples可以设为2-3(因为样本点数量少),eps用自动计算的方式能适配不同样本的密度差异,比固定值靠谱得多。
2. 局部离群因子(LOF)

LOF是通过比较每个点和其邻居的密度来判断离群:离群点的密度远低于周围点,哪怕周围是分散簇,也能准确区分。适合你这种存在不同密度簇的场景。

代码示例:

from sklearn.neighbors import LocalOutlierFactor

def filter_outliers_lof(points, n_neighbors=4):
    # n_neighbors设为3-5(样本点少,不能设置太大)
    lof = LocalOutlierFactor(n_neighbors=n_neighbors)
    # fit_predict返回1=正常点,-1=离群点
    return lof.fit_predict(points) == 1
3. 鲁棒版Z-score:中位数绝对偏差(MAD)

如果你不想引入sklearn的聚类库,可以用MAD替代标准差——它对异常值的鲁棒性远高于标准差,不会被分散簇拉偏全局统计量。

代码示例:

import numpy as np

def filter_outliers_mad(points, threshold=3.5):
    median = np.median(points, axis=0)
    # 计算中位数绝对偏差
    mad = np.median(np.abs(points - median), axis=0)
    # 避免MAD为0时除以0
    mad[mad == 0] = 0.01
    # 0.6745是正态分布下的缩放因子,让阈值和Z-score对齐
    z_mad = 0.6745 * np.abs(points - median) / mad
    # 两个维度都满足阈值才是有效点
    return np.all(z_mad <= threshold, axis=1)
为什么你的Z-score方法失效?

你用的全局均值+标准差会被「聚集簇」和「分散簇」共同影响:全局均值会偏向聚集簇,全局标准差会被分散簇拉大,导致分散簇里的正常点计算出的Z-score远超阈值,被误判成离群。而上面的方法要么基于局部密度,要么用鲁棒统计量,完美避开这个问题。

内容的提问来源于stack exchange,提问作者Dominik Ficek

火山引擎 最新活动