机器学习实战——python实现DBSCAN密度聚类

来源:互联网 发布:淘宝箱小型印刷机 编辑:程序博客网 时间:2024/05/16 02:20

基础概念

 ε-邻域:对于样本集中的xj, 它的ε-邻域为样本集中与它距离小于ε的样本所构成的集合。  核心对象:若xj的ε-邻域中至少包含MinPts个样本,则xj为一个核心对象。  密度直达:若xj位于xi的ε-邻域中,且xi为核心对象,则xj由xi密度直达。  密度可达:若样本序列p1, p2, ……, pn。pi+1由pi密度直达,则p1由pn密度可达。

算法过程

输入:样本集D={x1,x2,...,xm}    邻域参数(ε,MinPts).过程:初始化核心对象集合:Ω = Øfor j=1,2,...,m do    确定样本xj的ε-邻域N(xj);    if |N(xj)|>=MinPts then        将样本xj加入核心对象集合Ω    end ifend for初始化聚类簇数:k=0初始化未访问样本集合:Γ =Dwhile Ω != Ø do    记录当前未访问样本集合:Γold = Γ;    随机选取一个核心对象 o ∈ Ω,初始化队列Q=<o>    Γ = Γ\{o};    while Q != Ø do        取出队列Q中首个样本q;        if |N(q)|<=MinPts then            令Δ = N(q)∩Γ;            将Δ中的样本加入队列Q;            Γ = Γ\Δ;        end if    end while    k = k+1,生成聚类簇Ck = Γold\Γ;    Ω = Ω\Ckend while输出:簇划分C = {C1,C2,...,Ck}

算法实现

#计算两个向量之间的欧式距离def calDist(X1 , X2 ):    sum = 0    for x1 , x2 in zip(X1 , X2):        sum += (x1 - x2) ** 2    return sum ** 0.5#获取一个点的ε-邻域(记录的是索引)def getNeibor(data , dataSet , e):    res = []    for i in range(shape(dataSet)[0]):        if calDist(data , dataSet[i])<e:            res.append(i)    return res#密度聚类算法def DBSCAN(dataSet , e , minPts):    coreObjs = {}#初始化核心对象集合    C = {}    n = shape(dataSet)[0]    #找出所有核心对象,key是核心对象的index,value是ε-邻域中对象的index    for i in range(n):        neibor = getNeibor(dataSet[i] , dataSet , e)        if len(neibor)>=minPts:            coreObjs[i] = neibor       oldCoreObjs = coreObjs.copy()    k = 0#初始化聚类簇数    notAccess = range(n)#初始化未访问样本集合(索引)    while len(coreObjs)>0:        OldNotAccess = []        OldNotAccess.extend(notAccess)        cores = coreObjs.keys()        #随机选取一个核心对象        randNum = random.randint(0,len(cores))        core = cores[randNum]        queue = []        queue.append(core)        notAccess.remove(core)        while len(queue)>0:            q = queue[0]            del queue[0]            if q in oldCoreObjs.keys() :                    delte = [val for val in oldCoreObjs[q] if val in notAccess]#Δ = N(q)∩Γ                                queue.extend(delte)#将Δ中的样本加入队列Q                                notAccess = [val for val in notAccess if val not in delte]#Γ = Γ\Δ        k += 1        C[k] = [val for val in OldNotAccess if val not in notAccess]        for x in C[k]:            if x in coreObjs.keys():                del coreObjs[x]    return C

结果测试

测试数据(来源于西瓜书)

0.697,0.460.774,0.3760.634,0.2640.608,0.3180.556,0.2150.403,0.2370.481,0.1490.437,0.2110.666,0.0910.243,0.2670.245,0.0570.343,0.0990.639,0.1610.657,0.1980.36,0.370.593,0.0420.719,0.1030.359,0.1880.339,0.2410.282,0.2570.748,0.2320.714,0.3460.483,0.3120.478,0.4370.525,0.3690.751,0.4890.532,0.4720.473,0.3760.725,0.4450.446,0.459

数据处理

def loadDataSet(fileName):    dataMat = []    fr = open(fileName)    for line in fr.readlines():        curLine = line.strip().split(' ')        fltLine = map(float,curLine)        dataMat.append(fltLine)    return dataMat

画图方法

def draw(C , dataSet):    color = ['r', 'y', 'g', 'b', 'c', 'k', 'm']    for i in C.keys():        X = []        Y = []        datas = C[i]        for j in range(len(datas)):            X.append(dataSet[datas[j]][0])            Y.append(dataSet[datas[j]][1])        plt.scatter(X, Y, marker='o', color=color[i % len(color)], label=i)    plt.legend(loc='upper right')    plt.show()

测试代码

按照西瓜书设置的ε和MinPts参数
dataSet = loadDataSet("dataSet.txt")C = DBSCAN(dataSet , 0.11 , 5)draw(C , dataSet)

聚类结果

这里写图片描述

由于是随机选取核心对象,所以每次运行可能获得不同的聚类结果。
阅读全文
2 0
原创粉丝点击