DensityPeaks寻找outlier

DensityPeaks是一种基于密度的聚类方法,可用于检测异常值。该方法通过计算样本点的密度和距离来识别异常值,密度较低且距离较大的样本点被视为异常值。通过Python代码实现DensityPeaks算法,对数据进行聚类并识别异常值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DensityPeaks是一种基于密度的聚类方法,其也可以用于检测异常值。其基本思想就是认为那些距离样本群落较远且自身周围又没有多少样本的样本点很有可能就是异常值。要说明DensityPeaks,首先说明密度的概念,什么叫密度呢,实际上就是给定某个半径d_{c},则某个样本点的密度定义为以此样本点为圆心,以半径d_{c}做圆,落入圆内的样本点个数叫做这个样本点的密度,其数学定义如下所示:

\rho_{i}=\sum_{j}\chi (d_{ij}-d_{c})

\chi (x)=\left\{\begin{matrix} 1, x<0\\ 0, x\geq 0 \end{matrix}\right.

\rho_{i}为第i个样本点的密度。接下来,需要介绍每个样本点的另一个测量值\delta,其反应了当前样本点与所有密度大于它的样本点的距离的最小值,其数学表示如下所示:

\delta_{i}=\underset{j:\rho_{j}>\rho_{i}}{min}(d_{ij})

但是,对于密度最大点的\delta值定义为所有样本点与其距离的最大值,如下所示:

\delta_{i}=\underset{j}{max}(d_{ij})

那么,通过\rho_{i}以及\delta_{i}这两个指标就可以知道某个样本点是否距离其他样本群较远,其周围样本数目的多少。实际上那些距离较远,自身密度较大的样本点就可以作为聚类中心来进行聚类。例如找出密度\rho_{i}及距离\delta_{i}都很大的样本点作为聚类中心,可以采取DBSCAN找到其密度可达样本点集合从而将数据进行聚类。同理,我们可以将那些密度\rho_{i}较小,单距离\delta_{i}较大的样本点识别为异常值。

通过DensityPeaks识别异常值的python代码如下:


# coding: utf-8

# In[1]:


import numpy as np
from numpy import random as rd
import matplotlib.pyplot as plt


# In[2]:


def generate_samples():
    samples_1 = rd.normal(1, 0.05, (12, 2))
    samples_2 = rd.normal(1.4, 0.05, (12, 2))
    samples = np.concatenate([samples_1, samples_2], axis=0)
    fig = plt.figure(figsize=(8, 6))
    ax = plt.subplot(1, 1, 1)
    ax.scatter(samples[:, 0], samples[:, 1])
    for i in range(samples.shape[0]):
        plt.text(samples[i, 0], samples[i, 1], i)
    plt.show()
    return samples


# In[3]:


samples = generate_samples()


# In[4]:


def get_density(samples, r):
    densities = []
    for sample in samples:
        densities.append(list(np.sqrt(np.sum(np.square(sample - samples), axis=1)) < r).count(True))
    return densities


def get_delta(densities, samples):
    max_index = np.argmax(densities)
    deltas = []
    for i in range(len(densities)):
        if densities[i] == densities[max_index]:
            deltas.append(np.max(np.sqrt(np.sum(np.square(samples[i] - samples), axis=1))))
            continue
        deltas.append(np.min(np.sqrt(np.sum(np.square(samples[i] - samples[densities[i] < np.array(densities)]), axis=1))))
    return deltas


# In[5]:


densities = get_density(samples, 0.1)
deltas = get_delta(densities, samples)


# In[6]:


fig = plt.figure(figsize=(10, 6))
ax = plt.subplot(1, 1, 1)
ax.scatter(densities, deltas, alpha=0.5)
ax.set_xlabel("densities")
ax.set_ylabel("deltas")
for i in range(len(deltas)):
    plt.text(densities[i] * 1.01, deltas[i] * 1.01, i)
plt.show()


# In[7]:


def find_outlier_index(densities, deltas):
    """
        找异常值点索引,如果密度过小,且距离比自己密度大的所有样本点的距离的最小值过大则可能为异常值
    """
    min_density = np.min(densities)
    max_delta = np.max(deltas)
    density_thresh, delta_thresh = 1.5 * min_density, 0.08 * max_delta
    outlier_bool_index = list(np.logical_and(np.array(densities) < density_thresh, np.array(deltas) > delta_thresh))
    outlier_index = []
    count = 0
    while True:
        try:
            i = outlier_bool_index.index(True)
        except Exception:
            break
        else:
            outlier_bool_index.remove(True)
            outlier_index.append(i + len(outlier_index))
    return outlier_index


# In[8]:


outlier_index = find_outlier_index(densities, deltas)
print("可能的异常值点为:", outlier_index)

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值