实验二:大数据的处理
实验内容:
在本次实验中,请在k-mean算法、DBSCAN算法中选择任意一种算法完成聚类任务,并对于聚类结果实现可视化。
实验总体流程:
(1)完成对于pathbased、spiral、jain数据集的预处理。
(2)根据数据集中节点类别的数量确定簇的数量。
(3)编写程序实现k-means算法或DBSCAN算法。
(4)实现聚类结果的可视化(可视化结果如图所示)。
(5)分析聚类结果,观察并分析更改簇的数量后聚类结果的变化。
我选择的是DBSCAN算法,因为觉得k-mean只能处理球形簇,有些局限性
实验过程
-
核心思想:DBSCAN算法把点归为三类:边界点、核心点、噪声点。确定核心点主要与半径、最小点数两个参数有关,即点的半径内的点数要比最小点数大才为和核心点,而簇主要与核心点的位置有关,这里有一个密度可达的概念,是指核心点a的半径内有一个核心点b且b在另一个核心点c内,那就可以认为点a,b,c在同一个簇内。程序的核心思想也是这个
-
导入所需的库并准备数据
import numpy as np import math from matplotlib import pyplot as plt import matplotlib as mpl //画图中文显示 mpl.rcParams['font.sans-serif'] = ["SimHei"] mpl.rcParams["axes.unicode_minus"] = False t1 = np.loadtxt("./D31.txt") dataset = t1[:, 0:2] //创建一个布尔数组,是否被访问过,节省时间开销 visted = [False for i in dataset[:, 0]]
-
准备辅助函数
# 计算距离 def Euclidean_distance(a, b): return math.sqrt(np.power(a - b, 2).sum()) # 判断两个点是否相连 def is_neighbor(a, b, radius): return Euclidean_distance(a, b) < radius # 判断是否为核心点 def is_core(p_index, epx, minpts): nei_list = [] for i in range(np.size(dataset[:, 0])): if is_neighbor(dataset[p_index], dataset[i], epx): nei_list.append(i) if len(nei_list) < minpts + 1: return False return True # 返回输入核心点的边界点 def is_border(core_id, eps, size): border_pts = [] for i in range(size): if is_neighbor(dataset[core_id], dataset[i], eps): border_pts.append(i) return border_pts
-
首先找出所有的核心点
eps = 2.5 # 半径 minpts = 5 # 至少含有多少个点 core_lis = []# 存储核心点的数组 size = np.size(dataset) size = int(size / 2) print(type(size)) for i in range(size): if is_core(i, eps, minpts): core_lis.append(i) print(core_lis) fin_list = []# 最后的输出结果的数组
-
找出所有的密度可达的核心点构成一个簇,加入fin_list数组
for core_lis_id, i in enumerate(core_lis): if visted[i] == False:# 判断该点是否被处理过 temp_set = set()# 构建集合,为了去重,避免重复元素 visted[i] = True have_same = -1# 用来判断是否与最后结果数组有相同的元素,如果有则为一个簇 temp_set.add(i) for j in core_lis:# 遍历核心点数组 if visted[j] == False: if is_neighbor(dataset[i], dataset[j], eps): # 如果相邻则加入集合 temp_set.add(j) # 判断结果数组中存储的簇的元素是否有与临时集合中相同的元素,如果有则说明临时集合属于该簇 for fin_id, i in enumerate(fin_list): for k in temp_set: if k in i: have_same = fin_id if have_same != -1: for temp_item in temp_set: fin_list[have_same].add(temp_item) else: fin_list.append(temp_set)
-
根据核心点分好的簇处理边界点
for i in range(len(fin_list)): temp_lis = [] for j in fin_list[i]: temp_lis.append(j) temp_lis += is_border(j, eps, size) print(set(temp_lis)) temp_lis = list(set(temp_lis)) if len(temp_lis) == 1: plt.scatter(dataset[temp_lis[0], 0], dataset[temp_lis[0], 1], label=f'第{i + 1}个簇') else: plt.scatter(dataset[temp_lis[:], 0], dataset[temp_lis[:], 1], label=f'第{i + 1}个簇')
实验中遇到的困难:
关于核心点的半径和最小点数的确定,并没有想出在不引库的情况下一个完美的办法,所以只能手动调整