机器学习-聚类(密度聚类算法)

一,介绍

密度聚类算法有多种,我们这里主要介绍一种著名的密度聚类算法:DBSCAN。

首先,我们通过下图了解几个概念:

                                             

(1)邻域,与中心x距离不超过ε距离,如上图红色虚线圈

(2)核心对象,确定聚类的初始点,如上图的x1

(3)密度直达,在聚类核心对象邻域内的点,如上图x2由x1密度直达

(4)密度可达,可以通过几次密度直达后的点,如x3有x1密度可达

(5)密度相连,两个点可由一点通过密度可达方式分别到达,如x3和x4密度相连

算法流程

1,确定初始参数,邻域ε的值和核心对象密度直达最小值MinPTs的值;

2,根据初始参数,计算核心对象集合;

3,随机挑选一个核心对象作为种子,生成聚类族;

4,把包含在聚类族中的核心对象集合去除;

5,核心对象为空时,聚类结束。

二,代码实现

数据

0.697   0.46
0.774  0.376
0.634  0.264
0.608  0.318
0.556  0.215
0.403  0.237
0.481  0.149
0.437  0.211
0.666  0.091
0.243  0.267
0.245  0.057
0.343  0.099
0.639  0.161
0.657  0.198
0.36   0.37
0.593  0.042
0.719  0.103
0.359  0.188
0.339  0.241
0.282  0.257
0.748  0.232
0.714  0.346
0.483  0.312
0.478  0.437
0.525  0.369
0.751  0.489
0.532  0.472
0.473  0.376
0.725  0.445
0.446  0.459

Python代码:

import numpy as np
import math
import matplotlib.pyplot as plt

UNCLASSIFIED = False
NOISE = 0

# 读取数据
def loadDataSet(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())
    returnMat = np.zeros((numberOfLines, 2))
    classLabelVector = ['密度','含糖率']
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip().split('\t')
        returnMat[index, :] = line[0:2]
        index += 1
    return returnMat, classLabelVector

# 计算欧氏距离
def dist(a, b):
    return math.sqrt(np.power(a - b, 2).sum())

# 计算是否在邻域内
def eps_neighbor(a, b, eps):
    return dist(a, b) < eps

# 获取邻域内的点
def region_query(data, pointId, eps):
    nPoints = data.shape[1]
    seeds = []
    for i in range(nPoints):
        if eps_neighbor(data[:, pointId], data[:, i], eps):
            seeds.append(i)
    return seeds

# 分类结果
def expand_cluster(data, clusterResult, pointId, clusterId, eps, minPts):
    seeds = region_query(data, pointId, eps)
    if len(seeds) < minPts: # 不满足minPts条件的为噪声点
        clusterResult[pointId] = NOISE
        return False
    else:
        clusterResult[pointId] = clusterId # 划分到该簇
        for seedId in seeds:
            clusterResult[seedId] = clusterId

        while len(seeds) > 0: # 持续扩张
            currentPoint = seeds[0]
            queryResults = region_query(data, currentPoint, eps)
            if len(queryResults) >= minPts:
                for i in range(len(queryResults)):
                    resultPoint = queryResults[i]
                    if clusterResult[resultPoint] == UNCLASSIFIED:
                        seeds.append(resultPoint)
                        clusterResult[resultPoint] = clusterId
                    elif clusterResult[resultPoint] == NOISE:
                        clusterResult[resultPoint] = clusterId
            seeds = seeds[1:]
        return True

# DBSANC分类,data--数据;eps--范围;minPts--最小点
def dbscan(data, eps=0.11, minPts=5):
    clusterId = 1
    nPoints = data.shape[1]
    clusterResult = [UNCLASSIFIED] * nPoints
    for pointId in range(nPoints):
        point = data[:, pointId]
        if clusterResult[pointId] == UNCLASSIFIED:
            if expand_cluster(data, clusterResult, pointId, clusterId, eps, minPts):
                clusterId = clusterId + 1
    return clusterResult, clusterId - 1

def plotFeature(data, clusters, clusterNum):
    matClusters = np.mat(clusters).transpose()
    fig = plt.figure()
    scatterColors = ['black', 'blue', 'green', 'yellow', 'red', 'purple', 'orange', 'brown']
    ax = fig.add_subplot(111)
    for i in range(clusterNum + 1):
        colorSytle = scatterColors[i % len(scatterColors)]
        subCluster = data[:, np.nonzero(matClusters[:, 0].A == i)]
        ax.scatter(subCluster[0, :].flatten().A[0], subCluster[1, :].flatten().A[0], c=colorSytle, s=50)
    plt.show()

if __name__=="__main__":
    returnMat,classLabelVector = loadDataSet('watermelon4.0.txt')
    dataSet = np.mat(returnMat).transpose()
    clusters, clusterNum = dbscan(dataSet)
    plotFeature(dataSet, clusters, clusterNum)
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值