import numpy as np import matplotlib.pyplot as plt def build_data(): """ 准备数据 :return:准备好的数据 """ data_list = [] # 加载数据 with open("./test.txt") as f: # 将所有的元素读成一个列表 lines = f.readlines() # 循环对每一行元素进行单独处理 for line in lines: # print(line) # 去除line 前后的空白字符 line_obj = line.strip().split(' ') # print(line_obj) # print(type(line_obj)) # print("*"*20) # 把 line_obj 里面的每一个元素 转化为float,追加到一列表中 data_list.append([float(line_obj[0]), float(line_obj[1])]) # 列表嵌套列表的数据 ,每一个列表元素是原来的每一行元素 # print(data_list) # 将列表嵌套列表转化为二维数组 data_array = np.array(data_list) # print(data_array) # 将二维数组 转化为矩阵 data = np.mat(data_array) # print(data) # print(type(data)) return data def center_init(data, k): """ 初始化聚类中心 :param data: 所有的样本数据 :param k: 聚类的类别数目 :return: 聚类中心 """ # 随机在 data中挑选4行 作为初始化的聚类中心 # 获取data 的列数 columns_num = data.shape[1] # 获取data 的行数 index_num = data.shape[0] # 先初始化一个全为0 的中心,然后,后续替换里面的值 center = np.zeros(shape=(k, columns_num)) # 每次初始化一个聚类中心,需要循环初始化k次 for i in range(k): # 随机在80行里面选一个下标 # np.random.uniform() --->默认生成【0,1) 小数,可以更改最小值与最大值 r = int(np.random.uniform(0, index_num)) center[i, :] = data[r, :] return center def distance(v1, v2): """ 计算点1 跟点2 的距离 :param v1: 点1 :param v2: 点2 :return: 距离 """ dist = np.sqrt(np.sum(np.power((v1 - v2), 2))) return dist def k_means_owns(data, k): """ 自实现聚类算法 :param data: 所有的样本数据 :param k: 聚类的类别数目 :return: 聚类中心 、每一个样本属于哪一类别 """ # 获取data 的 行数 index_num = data.shape[0] columns_num = data.shape[1] # 1、初始化聚类中心 center = center_init(data, k) # print(center) # 需要将这个样本属于哪一类,而且距离也要保存起来吧 new_data = np.zeros(shape=(index_num,columns_num)) # 2、计算距离 # 每一个样本 都与每一个聚类中心进行计算距离 # 设置开关 flag = True while flag: flag = False # 关闭开关 for i in range(index_num): min_dist = 10000000000 min_index = -1 # i 代表每一行的样本的下标 for j in range(k): # 每一个样本需要 与每一个聚类中心进行计算距离 # 样本点data[i,:] 聚类中心center[j,:] dist = distance(data[i,:],center[j,:]) if dist < min_dist : min_dist = dist min_index = j if new_data[i,1] != min_index: flag = True # 打开 new_data[i,:] = min_dist,min_index # 调整聚类中心 for p in range(k): # p 0 1 2 3 # 找出属于同一类别 p_clustor = data[new_data[:,1] == p,:] # 计算这一类别的中心 # 先找出 这一类的簇第0 列的均值,与第1列的均值分别作为center 的行、列 center[p,:] = p_clustor[:,0].mean(),p_clustor[:,1].mean() return new_data,center def show_res(data,new_data,center): """ 结果展示 :param data: 原始数据 :param new_data: 主要包含了聚类距离与最终类别的数据 :param center: 最终的聚类中心 :return: None """ # 1、创建画布 plt.figure() # 2、绘图 # 获取原始数据的行数 index_num = data.shape[0] # colors = ['r','g','pink','y'] # 绘制散点图 # 一个点的绘制,需要给该点进行添加颜色 for i in range(index_num): plt.scatter(data[i,0],data[i,1],c=colors[int(new_data[i,1])]) # 绘制聚类中心 # plt.plot(center[:,0],center[:,1],'bx',markersize=12) # print(center[:,0]) # print(center[:,1]) # 3、展示 plt.show() def main(): """ 主函数 :return: """ # 1、构建数据 data = build_data() # 2、进行自实现k-means # 确定聚类的类别数目 k = 4 new_data, center = k_means_owns(data, k) print(new_data) print("*" * 80) print(center) # 3、结果展示 # 进行绘制结果图形展示 show_res(data,new_data,center) if __name__ == '__main__': main()