[Python数据挖掘] sklearn-DBSCAN聚类

[问题背景]

假定有这样的数据集,txt格式,ANSI编码:

YZN,133,108,76
ZHY,96,145,101
WYZ,132,107,60
DHY,100,102,120
CYH,139,99,93
LHY,73,149,81
ZHY,85,148,93
TQP,39,138,85
ZZL,145,112,71
HJC,101,116,118
XZY,99,98,117


每行第一列是学生姓名,第二列是语文成绩,第三列是数学成绩,第四列是英语成绩。

目标是利用KMeans对学生进行聚类,例如聚成3类。
[问题分析]

数据处理loadData()函数的设计在[Python数据处理] 怎样用Python预处理txt文档提取数据中已经讲过。

应用DBSCAN聚类器:

数据预处理grade.txt(需要和该py代码处于同一目录下)

if __name__ == '__main__':
    Name, Data = loadData('grade.txt')

设置DBSCAN聚类器所需要的参数eps(邻域半径)和min_samples(最小样本数)

eps = 21
min_samples = 2

DBSCAN聚类的原理请参见我在B站的投稿视频:DBSCAN聚类 动画演示

 用DBSCAN方法设置一个eps=21,min_samples=2的聚类器db,同时将预处理好的数据Data传入fit()接口

db = skc.DBSCAN(eps=eps_v, min_samples=min_samples_v).fit(Data)

返回的db中包含了标签labels_,用label承接

label = db.labels_

得到的标签label为: 

[ 0  1  0  2  0  1  1 -1  0  2  2]

按照标签对聚类结果分类整理并输出:

outputName = []
noise = []

for i in range(max(label)+1):
    outputName.append([])
for i in range(len(Name)):
    if(label[i] != -1):
        outputName[label[i]].append(Name[i])
    else:
        noise.append(Name[i])
print(outputName)
print("噪声点:", noise)

其中,因为DBSCAN是不需要预先指定聚类的类数的,所以标签的值有多少种并不能事先确定,一般来说标签为-1是噪声点,而其他值(从0递增)分别对应正常数据点的各个类别。所以标签种数需要利用max(label)确定,而且由于range()是左闭右开的,所以要max(label)+1

标签为-1的归类到噪声点类别中。 

输出分类结果:

[['YZN', 'WYZ', 'CYH', 'ZZL'], ['ZHY', 'LHY', 'ZHY'], ['DHY', 'HJC', 'XZY']]
噪声点: ['TQP']

 可以看到,DBSCAN分类结果与KMeans的分类结果大致相同,均筛选出了

英语较好的DHY, HJC, XZY;

语文较好的YZN, WYZ, CYH, ZZL;

数学较好的ZHY, LHY, ZHY。

而TQP由于过低的语文成绩39被归到了噪声点中,是DBSCAN聚类结果与KMeans聚类结果唯一的不同。

KMeans聚类的使用可以参见[Python数据挖掘] sklearn-KMeans聚类

相比较而言:

DBSCAN聚类结果稳定,不需要预先指定类别数目,但需要自己调参;

KMeans聚类结果有时不稳定,需要预先指定类别数目,不需要调参。

 

最后附上DBSCAN使用的完整代码如下:

import sklearn.cluster as skc

def loadData(filePath):
    fr = open(filePath, 'r+')
    lines = fr.readlines()
    retName = []
    retData = []
    for line in lines:
        items = line.strip().split(',')
        retName.append(items[0])
        retData.append([float(items[i]) for i in range(1,len(items))])
    return retName, retData

if __name__ == '__main__':
    Name, Data = loadData('grade.txt')
    
    eps = 21
    min_samples = 2
    db = skc.DBSCAN(eps=eps, min_samples=min_samples).fit(Data)
    label = db.labels_
    
    outputName = []
    noise = []

    for i in range(max(label)+1):
        outputName.append([])
    for i in range(len(Name)):
        if(label[i] != -1):
            outputName[label[i]].append(Name[i])
        else:
            noise.append(Name[i])
    print(outputName)
    print("噪声点:", noise)

 

你可能感兴趣的:(Python,Python,数据挖掘,入门,DBSCAN,scikit-learn,聚类,sklearn)