聚类的目标是使聚类后的各个簇,具有簇内聚合,簇间分离的特点。
如何度量簇之间,簇内样本之间的差异度?常用距离计算,最常用的是“闵可夫斯基距离”(Minkowski distance),其与向量范数相对应。
K均值算法的优化目标是最大化:簇内样本围绕簇均值向量的紧密程度
即最大化簇内样本的相似度
簇均值向量的定义如下:
设总样本集,划分为k个簇为,则簇的均值向量定义如下
为了求得最优解,需要考察样本的所有划分,这是一个NP难问题,K均值算法采用贪心策略迭代的求出近似的最优解。
算法流程如下:
随机在样本集中找k个样本作为初始的簇均值向量,k个样本代表划分为k个簇
k = 4
import random
a = range(n)
b = random.sample(a, k)
变量b以列表形式记录了k个随机数,提取k个样本作为初始的簇均值向量,并将数据形式从pandas.DataFrame转换为numpy.array,以便后续计算
U = []
for i in b:
U.append(np.array(data.loc[i].loc[[0, 1, 2, 3]]))
k个初始簇均值向量如下:
[array([5.8, 2.7, 5.1, 1.9], dtype=object),
array([4.9, 3.1, 1.5, 0.1], dtype=object),
array([4.4, 3.2, 1.3, 0.2], dtype=object),
array([5.2, 2.7, 3.9, 1.4], dtype=object)]
分别计算各个样本数据与这k个簇均值向量的差异(距离),将这个样本划分到距离最近的那个簇
C = [[] for _ in range(k)]#存储簇划分
dist = [0 for _ in range(k)]#存储距离
for i in range(n):
x = np.array(data.loc[i].loc[[0, 1, 2, 3]])
for j in range(k):
d = sum((x - U[j]) ** 2)
dist[j] = d
z = dist.index(min(dist))
C[z].append(data.loc[i])
重新计算各个簇的均值向量,重新计算各个样本与各个簇均值向量之间的差异(距离),重新划分样本数据,得到新的簇划分,
重复这个过程,直到簇划分逐渐趋于稳定,从而得到近似的最优簇划分。
U_new = [0 for _ in range(k)]
for i in range(k):
sumn = [0 for _ in range(4)]
for j in C[i]:
sumn = sumn + np.array(j.loc[[0, 1, 2, 3]])
sumn = sumn / len(C[i])
U_new[i] = sumn
U_new
for _ in range(100):
U = U_new
C = [[] for _ in range(k)]
dist = [0 for _ in range(k)]
for i in range(n):
x = np.array(data.loc[i].loc[[0, 1, 2, 3]])
for j in range(k):
d = sum((x - U[j]) ** 2)
dist[j] = d
z = dist.index(min(dist))
C[z].append(data.loc[i])
U_new = [0 for _ in range(k)]
for i in range(k):
sumn = np.array([0 for _ in range(4)])
for j in C[i]:
sumn = sumn + np.array(j.loc[[0, 1, 2, 3]])
sumn = sumn / len(C[i])
U_new[i] = sumn
在这里我没有设置迭代的终止条件,而是直接做了100次迭代,我们来看一下,最终划分的结果:
C0 = pd.DataFrame(C[0])
C0[4].value_counts()
Iris-virginica 36
Iris-versicolor 3
Name: 4, dtype: int64
第一个簇中,39个样本,36个是virginica,3个是versicolor,簇的纯度是比较高的,这符合我们对聚类结果的期望,用同样的方法,看看其他簇的样本分布:
C1 = pd.DataFrame(C[1])
C1[4].value_counts()
C2 = pd.DataFrame(C[2])
C2[4].value_counts()
C3 = pd.DataFrame(C[3])
C3[4].value_counts()
Iris-setosa 27
Name: 4, dtype: int64
Iris-setosa 23
Name: 4, dtype: int64
Iris-versicolor 47
Iris-virginica 14
Name: 4, dtype: int64
可以看到setosa类鸢尾花的划分是效果最好的,其他两类有划分交集,但是结果是可以接受的