机器学习 K均值聚类(K-means) 鸢尾花数据集

聚类的目标是使聚类后的各个簇,具有簇内聚合,簇间分离的特点。

如何度量簇之间,簇内样本之间的差异度?常用距离计算,最常用的是“闵可夫斯基距离”(Minkowski distance),其与向量范数相对应。

K均值算法的优化目标是最大化:簇内样本围绕簇均值向量的紧密程度

即最大化簇内样本的相似度

簇均值向量的定义如下:

设总样本集D=\left \{ x_{1},x_{2},\cdots ,x_{m} \right \},划分为k个簇为C=\left \{ C_{1},C_{2},\cdots ,C_{k} \right \},则簇C_{i}的均值向量定义如下

                                                                                       \mu _{i}=\frac{1}{\left | c_{i} \right |}\sum_{x\in C_{i}}x

为了求得最优解,需要考察样本的所有划分,这是一个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类鸢尾花的划分是效果最好的,其他两类有划分交集,但是结果是可以接受的

 

你可能感兴趣的:(Python语言,机器学习)