聚类的基本思想
俗话说“物以类聚,人以群分”
聚类--Clustering--是一种无监督学习,简单地说就是把相似的对象归到同一簇中。簇内的对象越相似,聚类的效果越好。
定义:给定一个有个对象的数据集,聚类将数据划分为个簇,而且这个划分满足两个条件:(1)每个簇至少包含一个对象;(2)每个对象属于且仅属于一个簇。
基本思想:对给定的,算法首先给出一个初始的划分方法,以后通过反复迭代的方法改变划分,使得每一次改进之后的划分方案都较前一次更好
K-Means算法
K-Means算法是最为经典的基于划分的聚簇方法,是十大经典数据挖掘算法之一。简单的说K-Means就是在没有任何监督信号的情况下将数据分为K份的一种方法。
聚类算法就是无监督学习中最常见的一种,给定一组数据,需要聚类算法去挖掘数据中的隐含信息。聚类算法的应用很广:顾客行为聚类,google新闻聚类等。
K值是聚类结果中类别的数量。简单的说就是我们希望将数据划分的类别数
算法实现
具体的算法步骤如下:
- 随机选择K个中心点
- 把每个数据点分配到离它最近的中心点;
- 重新计算每类中的点到该类中心点距离的平均值
- 分配每个数据到它最近的中心点;
- 重复步骤3和4,直到所有的观测值不再被分配或是达到最大的迭代次数(R把10次作为默认迭代次数)
- 以下代码数据集随机生成
-
1 import numpy as np 2 import matplotlib.pyplot as plt 3 4 # 两点距离 5 def distance(e1, e2): 6 return np.sqrt((e1[0]-e2[0])**2+(e1[1]-e2[1])**2) 7 8 # 集合中心 9 def means(arr): 10 return np.array([np.mean([e[0] for e in arr]), np.mean([e[1] for e in arr])]) 11 12 # arr中距离a最远的元素,用于初始化聚类中心 13 def farthest(k_arr, arr): 14 f = [0, 0] 15 max_d = 0 16 for e in arr: 17 d = 0 18 for i in range(k_arr.__len__()): 19 d = d + np.sqrt(distance(k_arr[i], e)) 20 if d > max_d: 21 max_d = d 22 f = e 23 return f 24 25 # arr中距离a最近的元素,用于聚类 26 def closest(a, arr): 27 c = arr[1] 28 min_d = distance(a, arr[1]) 29 arr = arr[1:] 30 for e in arr: 31 d = distance(a, e) 32 if d < min_d: 33 min_d = d 34 c = e 35 return c 36 37 38 if __name__=="__main__": 39 ## 生成二维随机坐标(如果有数据集就更好) 40 arr = np.random.randint(100, size=(100, 1, 2))[:, 0, :] 41 42 ## 初始化聚类中心和聚类容器 43 m = 5 44 r = np.random.randint(arr.__len__() - 1) 45 k_arr = np.array([arr[r]]) 46 cla_arr = [[]] 47 for i in range(m-1): 48 k = farthest(k_arr, arr) 49 k_arr = np.concatenate([k_arr, np.array([k])]) 50 cla_arr.append([]) 51 52 ## 迭代聚类 53 n = 20 54 cla_temp = cla_arr 55 for i in range(n): # 迭代n次 56 for e in arr: # 把集合里每一个元素聚到最近的类 57 ki = 0 # 假定距离第一个中心最近 58 min_d = distance(e, k_arr[ki]) 59 for j in range(1, k_arr.__len__()): 60 if distance(e, k_arr[j]) < min_d: # 找到更近的聚类中心 61 min_d = distance(e, k_arr[j]) 62 ki = j 63 cla_temp[ki].append(e) 64 # 迭代更新聚类中心 65 for k in range(k_arr.__len__()): 66 if n - 1 == i: 67 break 68 k_arr[k] = means(cla_temp[k]) 69 cla_temp[k] = [] 70 71 ## 可视化展示 72 col = ['HotPink', 'Aqua', 'Chartreuse', 'yellow', 'LightSalmon'] 73 for i in range(m): 74 plt.scatter(k_arr[i][0], k_arr[i][1], linewidth=10, color=col[i]) 75 plt.scatter([e[0] for e in cla_temp[i]], [e[1] for e in cla_temp[i]], color=col[i]) 76 plt.show()
- 训练结果:
-
K-Means的细节问题
-
K值怎么定?我怎么知道应该几类?
答:这个真的没有确定的做法,分几类主要取决于个人的经验与感觉,通常的做法是多尝试几个K值,看分成几类的结果更好解释,更符合分析目的等。或者可以把各种K值算出的SSE做比较,取最小的SSE的K值。 -
初始的K个质心怎么选?
答:最常用的方法是随机选,初始质心的选取对最终聚类结果有影响,因此算法一定要多执行几次,哪个结果更reasonable,就用哪个结果。 当然也有一些优化的方法,第一种是选择彼此距离最远的点,具体来说就是先选第一个点,然后选离第一个点最远的当第二个点,然后选第三个点,第三个点到第一、第二两点的距离之和最小,以此类推。第二种是先根据其他聚类算法(如层次聚类)得到聚类结果,从结果中每个分类选一个点。 -
K-Means会不会陷入一直选质心的过程,永远停不下来?
答:不会,有数学证明K-Means一定会收敛,大致思路是利用SSE的概念(也就是误差平方和),即每个点到自身所归属质心的距离的平方和,这个平方和是一个函数,然后能够证明这个函数是可以最终收敛的函数
-
参考: