k-means 聚类算法(Python实现,详解)

import numpy as np
import matplotlib.pyplot as plt

# 两点距离
def distance(e1, e2):

    return np.sqrt((e1[0]-e2[0])**2+(e1[1]-e2[1])**2) #欧式距离,较为准确

 #return np.abs(e1[0]-e2[0])+np.abs(e1[1]-e2[1]) #曼哈顿距离  
 #return np.abs(e1[0]-e2[0]) if np.abs(e1[0]-e2[0])>np.abs(e1[1]-e2[1]) else np.abs(e1[1]-e2[1]) #切比雪夫距离

 

# 集合中心
def means(arr):
    return np.array([np.mean([e[0] for e in arr]), np.mean([e[1] for e in arr])])

# arr中距离a最远的元素,用于初始化聚类中心
def farthest(k_arr, arr):
    f = [0, 0]
    max_d = 0
    for e in arr: #第一层循环
        d = 0
        for i in range(k_arr.__len__()): #第二层循环
            d = d + np.sqrt(distance(k_arr[i], e)) #把e到k_array里面每一个元素的距离累加
        if d > max_d: #如果当前元素比已经扫描过的元素距离远 ,更新最远距离
            max_d = d #更新最远距离元素
            f = e
    return f #返回arr中离 k_arr中所有元素 最远的元素

# arr中距离a最近的元素,用于聚类 a为聚类中心
def closest(a, arr): 
    c = arr[1]
    min_d = distance(a, arr[1])
    arr = arr[1:]
    for e in arr:
        d = distance(a, e)
        if d < min_d:
            min_d = d
            c = e
    return c

# 切片说明 arr[start:end:step] 
# start缺省 :index=0 开始 
# end缺省 :index=len(arr)-1
# step缺省 :步长为+1
#例子 In: a=[10,20,30,40,50,60,70]
# In:a[:]  
#  => out:[10,20,30,40,50,60,70]

# In:a[::]   
# => out:[10,20,30,40,50,60,70]

# In:a[-1]   #最后一个元素
# => out:70

# In:a[:-2]   #相当于[0,-2) -1最后一个 -2倒数第二个
# => out:[10,20,30,40,50]

# In:a[::-1]  #逆序输出 逆序切皮 相当于 a[6:0:-1]
#  => out:[70,60,50,40,30,20,10]

# In:a[2::-1]  #逆序输出 相当于 a[2:0:-1]
#  => out:[30,20,10]

  
   

if __name__=="__main__":
    ## 生成二维随机坐标,手上有数据集的朋友注意,理解arr改起来就很容易了
    ## arr是一个数组,每个元素都是一个二元组,代表着一个坐标
    ## arr形如:[ (x1, y1), (x2, y2), (x3, y3) ... ]
    arr = np.random.randint(100, size=(100, 1, 2))[:, 0, :]

    ## 初始化聚类中心和聚类容器
    m = 5
    r = np.random.randint(arr.__len__() - 1)#随机选择聚类中心 ,可以通过k-means++的方法对随机选择中心点进行优化
    k_arr = np.array([arr[r]]) #取出选择的聚类中心
    cla_arr = [[]]
    for i in range(m-1):
        k = farthest(k_arr, arr) #由一个聚类中心选择一个新的聚类中心
        k_arr = np.concatenate([k_arr, np.array([k])]) #数组拼接  把聚类中心 拼接在k_arr数组里
        cla_arr.append([])#每找到一个聚类中心,增加一个类

    ## 迭代聚类
    n = 20
    cla_temp = cla_arr
    for i in range(n):    # 迭代n次
        for e in arr:    # 把集合里每一个元素聚到最近的类
            ki = 0        # 假定距离第一个中心最近
            min_d = distance(e, k_arr[ki])
            for j in range(1, k_arr.__len__()):
                if distance(e, k_arr[j]) < min_d:    # 找到更近的聚类中心
                    min_d = distance(e, k_arr[j])
                    ki = j
            cla_temp[ki].append(e) #将元素加入最近的聚类中心的类中
        # 迭代更新聚类中心
        for k in range(k_arr.__len__()):
            if n - 1 == i:
                break
            k_arr[k] = means(cla_temp[k])  
            cla_temp[k] = []
            # 原聚类中心 为 firstcenter 
            # 通过迭代等到了 一个包含众多满足聚类条件的集合 
            # 通过整个集合的数据求出 当前集合的中心 
            # 作为新聚类中心  newcenter 
            # 即firstcenter 为聚类条件判断的起始点 而newcneter 为集合实际中心 
            # 更新聚类中心结果如图一 不更新聚类结果如图二
            

    ## 可视化展示
    col = ['HotPink', 'Aqua', 'Chartreuse', 'yellow', 'LightSalmon']
    for i in range(m):
        plt.scatter(k_arr[i][0], k_arr[i][1], linewidth=10, color=col[i]) #画聚类中心点
        plt.scatter([e[0] for e in cla_temp[i]], [e[1] for e in cla_temp[i]], color=col[i]) #类中元素
    plt.show()


参考,转载
k-means聚类算法python实现

你可能感兴趣的:(python,算法,线性代数)