机器学习-K-means-2020-5-7

​一:聚类的目的

使同一类对象近可能的大,不同对象之间的相似度尽可能的小

二:聚类的分类:

1 : 基于划分 

K-Means ,K-Medoids,CLarans

2: 基于层次

BIRCH , CURE ,CHAMELEON

3: 基于密度

DBscan ,Optics , DenClue

推荐网站可视化:

https://www.naftaliharris.com/blog/visualizing-k-means-clustering/

比较好玩,形象化!!!

 

 

三:K -mans:  基于划分的聚类,无监督学习算法(硬聚类)

适用数据集:球状分布的数据,没有标签

K-Means works best in datasets that have with clusters that are roughly equally-sized and shaped roughly regularly.(每个类数量大致相等,形状规则)

数据集X: 

基本思想: 

 

The k-means algorithm captures the insight that each point in a cluster should be near to the center of that cluster. (所有样本点到中心点的距离最小)

策略:采用欧式距离平方和最小 squared Euclidean distance

The k-means algorithm divides a set of N samples X into K disjoint clusters C(数据集n个样本,划分成C个族,每个族中心为uj)

(简单理解: 每个样本点到它的所分类中心的距离之和)

李航<<统计学习方法>>:

X = {x1, x2,x3 .....xn} , xi 是m维特征,无标签数据集

K均值聚类的目标是将n个数据集划分到k个不同的簇(cu) cluster, 或者叫类中k < n 。

定义样本之间距离欧式距离: 

损失函数:

优化问题:        C*  = arg min W(C)

算法流程:

(1)随机选取K个样本点,作为初始化聚类 中心。
(2)数据集中每个样本点测量其到每个聚类中心的距离,并把它划分到最近的中心。
(3)重新计算,每个类中所有点的均值作为这个类的聚类中心。
(4)迭代(2)~(3)步直至新的中心与原中心相等或小于指定阈值,算法结束。

注意一下几个问题?

1:初始化K个聚类中心(centroids) 的选择? 

  • 随机选择空间中任意k个位置作为距离中心

  • 随机从数据集 中选择k个聚类中心

  • 最远中心(1:数据集随机选择一个点作为聚类中心。然后在剩下数据中选择距离第一个聚类中心最远的点,作为第二个聚类中心, 循环以上,直到选择k个聚类中心)

初始聚类中心: 不同的方法对收敛速度,聚类结果都有很大影响

k-means++ 最好的初始化聚类中心(基本思想就是:初始的聚类中心之间的相互距离要尽可能的远)

2: 距离

  • 欧式距离

  • 余弦相似度(文本数据)

3:k值选择

事先不知道数据集能划分多少聚类,K是试探性 的,然后比较损失函数选出合适的k值

4: 优缺点

优点:

原理比较简单,实现也是很容易,收敛速度快

 主要需要调参的参数仅仅是k

缺点:

  • K值的选取不好把握

  • 对于不是凸的数据集比较难收敛(改进:基于密度的聚类算法更加适合,比如DESCAN算法)

  • 如果各隐含类别的数据不平衡,比如各隐含类别的数据量严重失衡,或者各隐含类别的方差不同,则聚类效果不佳。

  • 采用迭代方法,得到的结果只是局部最优。

  •  对噪音和异常点比较的敏感(改进1:离群点检测的LOF算法,通过去除离群点后再聚类,可以减少离群点和孤立点对于聚类效果的影响;改进2:改成求点的中位数,这种聚类方式即K-Mediods聚类(K中值))

  • 初始聚类中心的选择(改进1:k-means++; 改进2:二分K-means)

 

四:代码实现:

一:初聚类中心初始化最远

聚类中心的选择,第一个中心: centrod1,数据集中随机选择一个

第二个中心: centrod2,为数据集中到第centrod1最远的点

第三个中心 :centrod3 ,为数据集中到 centrod1,centrod2 距离之和最大的点

'''

第k个中心:centrodk ,数据集中到(centrod1,centrod2,...centrodk-1)距离之和最大的点

import numpy as npimport matplotlib.pyplot as pltimport randomfrom sklearn import datasets#两点之间的距离欧式距离def distance(point1,point2):    """    e1: 数据1  向量    e2: 数据2    return : distance(point2,point2)    """    e1 = np.array(point1)    e2 = np.array(point2)    return np.sqrt(np.sum((point1-point2)**2))#聚类中心def meanCenter(class_one):    """    class_one: 一个聚类的所有样本点    return : 这个聚类所有样本点的均值    """    arr = np.array(class_one)    mean = arr.mean(axis=0)    return mean#最远中心法,用于初始化聚类中心def farCenter(centrods,data_set):    """    centrods: k个聚类中心数组    data_set: 整个数据集    return: 一个样本点: 离已经有的聚类中心距离求和,最远的点    """    m = np.shape(data_set)[1]  #特征维度    temp_point =np.zeros([m]) # 临时保存样本点数据    max_dist = 0    for point in data_set:        dist =0         for i in range(len(centrods)):            dist += np.sqrt(distance(centrods[i],point)) #到已经有的聚类中心求和,开平方为了简化计算        if dist >max_dist:            max_dist = dist            temp_point =point    return temp_pointdata_set = datasets.load_iris().datak= 3  # 聚类中心的个数,人为设置# 随机选项一个点,初始化聚类中心rand_point = random.choice(data_set)clusterCenter_K =np.array([rand_point])class_arr = [[]]                 #保存每个聚类的最近样本点 例:cla[1][...] 第1 个类中的样本点# 初始化聚类中心,数据集中选择距离最大的k个点for i in range(k-1):    far_point = farCenter(clusterCenter_K,data_set)    clusterCenter_K =np.concatenate([clusterCenter_K,np.array([far_point])])    class_arr.append([])#可视化初始化数据col = ['HotPink', 'Aqua', 'Chartreuse', 'yellow', 'LightSalmon']plt.scatter(data_set[:,0],data_set[:,1],label='origin data',c='g')plt.legend(loc = 'upper left') for i in range(k):    plt.scatter(clusterCenter_K[i][0],clusterCenter_K[i][1],linewidth=10, color=col[i])plt.show()#迭代epochs = 50for epoch in range(epochs):    #1:更新样本点所属类,离聚类中心最近,则划分到这个聚类中    for point in data_set:        ki = 0        mid_dist =distance(point,clusterCenter_K[ki])   # 找出离聚类中心最近的聚类        for j in range(1,len(clusterCenter_K)):            dist =distance(point,clusterCenter_K[j])            if dist <mid_dist:                mid_dist = dist                ki = j        class_arr[ki].append(point) #将样本点划入 最近Ki类中    #2更新聚类中心    for i in range(len(clusterCenter_K)):        if epochs-1 == epoch:# 最后一次不更新            break         clusterCenter_K[i]= meanCenter(class_arr[i])        class_arr[i] = []## 可视化展示col = ['HotPink', 'Aqua', 'red', 'yellow', 'LightSalmon']for i in range(k):    plt.scatter(clusterCenter_K[i][0], clusterCenter_K[i][1], linewidth=10, color=col[i])    plt.scatter([e[0] for e in class_arr[i]], [e[1] for e in class_arr[i]], color=col[i])plt.show()

二: k-means ++ 

k-means++算法选择初始seeds的基本思想就是:初始的聚类中心之间的相互距离要尽可能的远。

算法步骤:

(1)从输入的数据点集合中随机选择一个点作为第一个聚类中心

(2)对于数据集中的每一个点x,计算它与最近聚类中心(指已选择的聚类中心)的距离D(x)

(3)选择一个新的数据点作为新的聚类中心,选择的原则是:D(x)较大的点,被选取作为聚类中心的概率较大

(4)重复2和3直到k个聚类中心被选出来

   (5) 与K-means一样,聚类中心更新,和在划分类。

从上面的算法描述上可以看到,算法的关键是第3步,如何将D(x)反映到点被选择的概率上,一种算法如下:

  1. 数据集中随机选择一个样本点,作为种子点

  2. 对于数据集中每个样本点,我们都计算其和最近的一个“种子点”的距离D(x)并保存在一个数组里,然后把这些距离加起来得到Sum(D(x))。

  3. 再取一个概率随机值P, 属于[0,1],用权重的方式来取计算下一个“种子点”。这个算法的实现是,total =Sum(D(x))*P ,然后用total -= D(x),直到其<=0,此时的点就是下一个“种子点”。

import mathimport randomfrom sklearn import datasetsimport numpy as npimport matplotlib.pyplot as pltdef distance(point1,point2)->float:    """    point1: 样本点1     point2: 样本点2    return:distance(point1,point2) 欧式距离    """    dist = 0.0    for e1,e2 in zip(point1,point2):        dist += (e1-e2)**2    return math.sqrt(dist)def closest_distance(point,centroids):    """    计算样本点到所有聚类中心最短距离    """    min_dist = math.inf #初始设置成无穷大    for _, centroid in enumerate(centroids):        dist = distance(centroid,point)        if dist < min_dist:            min_dist = dist    return min_dist#初始化聚类中心def k_Centers(data_set:list ,k : int)->list:    """    从数据集 中返回k个对象作为质心    """    cluster_centers = []    cluster_centers.append(random.choice(data_set)) # 第一个聚类中心在数据集中随机选择一个    d =[0 for  i in range(len(data_set))]     # 初始化为0    for _ in range(1,k):        total = 0        for i ,point in enumerate(data_set):            d[i] = closest_distance(point,cluster_centers)#样本点到所有聚类中心最近的点            total +=d[i]        total *=random.random() # total * [0,1]的概率        for i ,di in enumerate(d):            total -= di            if total > 0:                continue            cluster_centers.append(data_set[i])            break     return cluster_centers#更新聚类中心def meanCenter_updata(subsetData:list):    """    subsetData: 一个聚类中所有的样本    return : 这个聚类中所有样本的平均值    """    data = np.array(subsetData)    mean = data.mean(axis=0)    return meandata_set = datasets.load_iris().data # 加载数据epochs = 50class_arr = [[]] #保存每个类的样本数据k= 3  # 聚类个数cluster_centers = k_Centers(data_set,k) #初始化聚类中心 initial cluster centerfor _ in range(len(cluster_centers)):    class_arr.append([])#绘制初始聚类中心分布图col = ['HotPink', 'red', 'Chartreuse', 'yellow', 'LightSalmon']for i in range(len(cluster_centers)):    plt.scatter(cluster_centers[i][0],cluster_centers[i][1],linewidth=10, color=col[i])plt.scatter(data_set[:,0],data_set[:,1],c="g",marker='o',label='origin data')plt.xlabel('sepal length')plt.ylabel('sepal width')plt.legend(loc=2)plt.show()for epoch in range(epochs):    for point in data_set:  #1将数据划分到最近聚类中心        index = 0        min_dist = distance(point,cluster_centers[0])        for i in range(1,len(cluster_centers)):            dist = distance(point,cluster_centers[i])            if dist < min_dist:                min_dist =dist                index = i        class_arr[index].append(point)    for j in range(len(cluster_centers)): #2:更新聚类中心        if epoch == epochs -1 :            break        cluster_centers[j] = meanCenter_updata(class_arr[j])        class_arr[j] = []#结果可视化for i in range(k):    plt.scatter(cluster_centers[i][0], cluster_centers[i][1], linewidth=10, color=col[i])    plt.scatter([e[0] for e in class_arr[i]], [e[1] for e in class_arr[i]], color=col[i])plt.show()

3: scikit-learn

官网手册:https://scikit-learn.org/stable/modules/clustering.html#k-means

使用:

导包 : from sklearn.cluster import KMeans

KMeans() 

参数: paramters 

  • n_clusters  = 8 default 

  • max_iter:  300  最大迭代数

  • n_init : 10  用不同质心初始化运算比较次数,选择一个损失函数最小的 inertia

  • init:始化方法k-means++ , random , ndarray向量(n_cluster,n_features)自定义

  • precopute_distance: 预计算距离,计算速度快,但占内存。auto ,True ,False

  • tol: float default 1e-4 

  • n_jobs : -1 cpu计算  +1 ,不进行并行运算

  • copy_x: True default 当我们precomputing distances时,将数据中心化会得到更准确的结果。如果把此参数值设为True,则原始数据不会被改变。如果是False,则会直接在原始数据

属性: attributes

  • cluster_centers_:

  • Labels_ : 每个点的分类

  • inertia_ 

方法: methods

  • fit()

  • fit_predictt()

  • fit_transform()

  • get_params()

  • predict()

  • score()

  • set_params()

  • transform()

iris数据集k-means聚类

import matplotlib.pyplot as pltimport numpy as npfrom sklearn.cluster import KMeansfrom sklearn import datasetsfrom  sklearn.metrics import confusion_matrixiris = datasets.load_iris()data = iris.data#绘制数据分布图plt.scatter(data[:,0],data[:,1],c="red",marker='o',label='see')plt.xlabel('sepal length')plt.ylabel('sepal width')plt.legend(loc=2)plt.show()estimator = KMeans(n_clusters=3,max_iter=400,n_init=11,init="k-means++") # 构造聚类器estimator.fit(data)label_pred = estimator.labels_ # 获取聚类标签 每个点的分类cluster_center = estimator.cluster_centers_ # 获取聚类中心color =['r','g','b']i = 0for e in cluster_center:    plt.scatter(e[0],e[1],linewidth=10,c=color[i])    i+=1# 绘制聚类结果X0 = data[label_pred ==0]X1 = data[label_pred ==1]X2 = data[label_pred ==2]plt.scatter(X0[:,0],X0[:,1],c='r',marker='o',label='label0')plt.scatter(X1[:,0],X1[:,1],c='g',marker='+',label='label1')plt.scatter(X2[:,0],X2[:,1],c='b',marker='*',label='label2')plt.xlabel('sepal length')plt.ylabel('sepal width')plt.legend(loc=2)print('聚类结果,混淆矩阵')print(confusion_matrix(iris.target,label_pred))#print(estimator.predict(data))print(estimator.score(data))print(estimator.get_params())#print(estimator.fit_transform(data))

Reference:

[1]:https://towardsdatascience.com/the-5-clustering-algorithms-data-scientists-need-to-know-a36d136ef68

[2]:https://medium.com/m/global-identity?redirectUrl=https%3A%2F%2Ftowardsdatascience.com%2Fthe-5-clustering-algorithms-data-scientists-need-to-know-a36d136ef68

[3] https://blog.csdn.net/github_39261590/article/details/76910689

[4] https://blog.csdn.net/loadstar_kun/article/details/39450615

[5] https://blog.csdn.net/itplus/article/details/10088429

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值