k均值算法——python实现

无监督学习中应用最多的就是聚类,其中k均值算法就是典型的聚类算法,下面是一段从文本中读取30数据,然后进行聚类的过程,包括输出读取的数据集、随机选择的K个初始均值向量、30行数据各自所属的类别以及最后的聚类中心,因为每次是随机选择K个初始均值向量,所以每次运行结果不一样的。

如果各位需要全部引用的话,请标注来源,具体的数据集需要的话,可以找我要。
import numpy as np
import math
# 读取文件
def load_dataset(file_name):
    data_list = []
    fr=open(file_name,encoding='utf-8-sig')
    lines = fr.readlines()
    for line in lines:
        pas_line = line.strip().split("\t")
        flt_line = list(map(eval, pas_line))
        data_list.append(flt_line)
    return np.array(data_list)
# 路径输入及函数调用后打印
data_set = load_dataset(r"F:\test\1.txt")
print(data_set)
# 计算两个向量之间的欧氏距离
def dist_eclud(vecA, vecB):
    vec_square = []
    for element in vecA - vecB:
        element = element ** 2
        vec_square.append(element)
    return sum(vec_square) ** 0.5

# 构建k个随机质心
def rand_cent(data_set, k):
    n = data_set.shape[1]
    # n = data_set.shape 这时n的值为(30,2)即第0轴有30行,第1轴两列。所以要按照上面形式的话,n值为2
    centroids = np.zeros((k, n))
    for j in range(n):
        # 找每一列的最小值,对于此数据集是0.243和0.042
        min_j = float(min(data_set[:,j]))
        # print(min_j)
        # 找到数据集每一维的最小和最大值。然后得到每一维(每一列)的取值范围。
        # 用0到1之间的随机数和取值范围相乘,再用最小值加上该乘积,就可以得到在每一维取值范围内的随机数。
        range_j = float(max(data_set[:,j])) - min_j
        # print(range_j)即0.531和0.447,np.random.rand(k, 1))生成3*1的数组
        centroids[:,j] = (min_j + range_j * np.random.rand(k, 1))[:,0]
        # print(np.random.rand(k, 1))
        # print( np.random.rand(k, 1)[:,0])
    print("随机选择的初始均值向量为:\n",centroids)
    return centroids

def Kmeans(data_set, k):
    # m值为30
    m = data_set.shape[0]
    # 初始化为30*2的全为0的数组,注意里面是元组
    cluster_assment = np.zeros((m, 2))
    # 调用后找到了随机的初始均值向量
    centroids = rand_cent(data_set, k)
    cluster_changed = True
    while cluster_changed:
        cluster_changed = False
        # 从0到29的有序序列依次取出元素赋给i
        for i in range(m):
            min_dist = np.inf; min_index = -1
            # print(min_dist)
            # 初始均值向量就k个,即3个
            for j in range(k):
                # 初始均值向量数组中取出每行两列元素与数据集中的所有行两列的元素计算距离
                dist_ji = dist_eclud(centroids[j,:], data_set[i,:])
                # 如果距离最小则标上当时的均值向量的行标记
                if dist_ji < min_dist:
                    min_dist = dist_ji; min_index = j
            if cluster_assment[i,0] != min_index:
                cluster_changed = True
            # 所属类以及欧氏距离平方
            cluster_assment[i,:] = min_index, min_dist**2
        # 计算新均值向量
        for cent in range(k):
            # 这是在求每次分别属于某个类别的数据,然后再以此为基础计算新的均值向量
            pts_inclust = data_set[np.nonzero(list(map(lambda x:x==cent, cluster_assment[:,0])))]
            # print(pts_inclust)
            # 按列求平均值,即新的均值向量
            centroids[cent,:] = np.mean(pts_inclust, axis=0)
    return centroids, cluster_assment
# 首先初始化样本点的簇分配矩阵(cluster_assment),有30行2列,第一列为该样本点的簇分配索引,第二列为该样本点到该簇质心的欧氏距离。
# 当任意一个点的簇分配发生变化时,迭代执行以下操作:遍历每个样本点,计算样本点i到各个质心的距离,找到最小距离,
# 将该质心所在簇编号分配给该样本点。遍历完所有样本点后,重新计算每个簇的质心。直到所有样本点的簇分配都不再发生变化时迭代停止。
# 最后返回质心和样本点的簇分配矩阵
my_centroids, my_cluster = Kmeans(data_set, 3)
print("30行数据各自所属类别为:\n",my_cluster[:,0])
print("聚类中心为:\n",my_centroids)


猜你喜欢

转载自blog.csdn.net/N_jessica/article/details/80927051
今日推荐