Kmeans聚类原理及python实现代码

时间:2024-03-14 16:53:40

kmeans 原理:

(1)首先,随机确定k个初始点的质心;

(2)然后将数据集中的每一个点分配到一个簇中,即为每一个点找到距其最近的质心,并将其分配给该质心所对应的簇;

(3)对每一个簇,计算簇中所有点的均值并将均值作为质心(例:在三维空间里,计算各个点的x的均值得到x1,y的均值得到y1,z的均值得到z1,以此得到新的坐标点 x1,y1,z1,然后重新计算各个点距离最近的族)

(4)重复步骤(2),(3),直到没有变化为止

 

 

代码处理思路

kmeans 聚类处理流程

数据源都处理好后的步骤:

第一步:通过SSE,轮廓系数等方法  选择最佳k值

第二步:根据第一步选择合适的k值,进行聚类

第三步:一般通过轮廓系数检验聚类效果,范围在[-1,1],一般越接近于1,聚类效果越好,将对应的分组类别合并到对应数据,并写入文件

第四步:画概率密度图,根据概率密度图分析每一个用户群的特点 or/and 画聚类分布图

#-*- coding:utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pylab as pyl


'''
kmeans 聚类处理流程
数据源都处理好后的步骤:
第一步:通过SSE方法 选择最佳k值
第二步:根据第一步选择合适的k值,进行聚类
第三步:通过轮廓系数检验聚类效果,范围在[-1,1],一般越接近于1,聚类效果越好,将对应的分组类别合并到对应数据,并写入文件
第四步:画概率密度图,根据概率密度图分析每一个用户群的特点 or/and 画聚类分布图
'''

#原数据处理
data = pd.read_csv('聚类测试数据3.csv',index_col='userid')
data2= 1.0*(data - data.mean())/data.std() #数据标准化  #z-score标准化法 z-score 标准化(zero-mean normalization)也叫标准差标准化,经过处理的数据符合标准正态分布,即均值为0,标准差为1
data1=data2[data2.columns[:]].as_matrix()

#from sklearn.cluster import Birch
from sklearn.cluster import KMeans
#调用轮廓系数所需包
from sklearn.metrics import silhouette_samples, silhouette_score


#第一步----------选择最佳k值
#手肘法选择最佳k值
'''
SSE = []  # 存放每次结果的误差平方和  
for k in range(1,9):  
    estimator = KMeans(n_clusters=k)  # 构造聚类器  
    estimator.fit(data1)  
    SSE.append(estimator.inertia_)  
X = range(1,9)  
plt.xlabel('k')  
plt.ylabel('SSE')  
plt.plot(X,SSE,'o-')  
plt.show()  
'''

#轮廓系数检验聚类效果
'''
"""silhouette 是一个衡量一个结点与它属聚类相较于其它聚类的相似程度。 
取值范围-1到1,值越大表明这个结点更匹配其属聚类而不与相邻的聚类匹配。 
如果大多数结点都有很高的silhouette value,那么聚类适当。若许多点都有低或者负的值,说明分类过多或者过少。
"""
clusters=[2,3,4,5,8]
subplot_counter=1
sc_scores=[]
for t in clusters:
  s = 0
  for i in range(5):
    kms=KMeans(n_clusters=t,max_iter=20).fit(data1)#调用kmeans包#一般迭代20次以上就收敛了,聚类5-10次,但10次运行效率会低
    sc_score = silhouette_score(data1, kms.labels_,metric='euclidean')#计算单次所有样本的轮廓系数的平均值
    s=s+sc_score
  sc_score1=np.mean(s)
  sc_scores.append(sc_score1)
plt.figure()
plt.plot(clusters,sc_scores,'*-')
plt.xlabel('Number of Clusters')
plt.ylabel('Sil C Score')
plt.show()
'''


#平均距离检验聚类效果(检验效果粗糙,但运行速度快)
'''
from scipy.spatial.distance import cdist
clusters=[2,3,4,5,8,12,17]
meandist=[]
for t in clusters:
  kms=KMeans(n_clusters=t).fit(data1)
  meandist.append(sum(np.min(cdist(data1,kms.cluster_centers_,metric='euclidean'),axis=1))/data1.shape[0])
plt.figure()
plt.plot(clusters,meandist,'*-')
plt.xlabel('clusters')
plt.ylabel('Average Dispersion')
plt.show()
'''

#------------上面三种方法判断k值最佳取值,取完值直接确定k值,用简单的程序跑,提高效率。上面确定出来k=3的时候效果最好


#第二步---------确定好轮廓系数后,输入合适的k值,进行聚类。(简单粗暴的轮廓系数检验法,一般不推荐使用)
k=3
kms=KMeans(n_clusters=k,max_iter=20) #,n_jobs=2,max_iter=200
y=kms.fit_predict(data1)
print(y)

#第三步---输出分类结果,并检验
silhouette_avg = silhouette_score(data1, y)#轮廓系数检验聚类效果     #print(silhouette_avg)
print('----',silhouette_avg)


#简单打印结果
r1=pd.Series(kms.labels_).value_counts()#统计各个类别的数目
r2=pd.DataFrame(kms.cluster_centers_) #找出聚类中心
r=pd.concat([r2,r1],axis=1)#横向连接(0是纵向),得到聚类中心对应的类别下的数目
r.columns = list(data.columns) + [u'类别数目'] #重命名表头
print(r)


#详细输出原始数据及其类别
r = pd.concat([data, pd.Series(kms.labels_, index = data.index)], axis = 1)  #详细输出每个样本对应的类别
r.columns = list(data.columns) + [u'聚类类别'] #重命名表头
r.to_csv('聚类测试数据结果.csv') #保存结果


#第四步---画图

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号


#画概率密度图,方便分析人群特点
def density_plot(data): #自定义作图函数
  p = data.plot(kind='kde', linewidth = 3,figsize=(20, 50), subplots = True, sharex = False)
  plt.subplots_adjust(hspace=1)  # 设置两个子图的间距
  [p[i].set_ylabel(u'密度') for i in range(k)]
  plt.legend()
  return plt

pic_output = '聚类结果密度图_类别' #概率密度图文件名前缀
for i in range(k):
  density_plot(data[r[u'聚类类别']==i]).savefig(u'%s%s.png' %(pic_output, i))

#https://blog.csdn.net/watermelon12138/article/details/86549474 如何看概率密度图


# 使用TSNE进行数据降维并展示聚类结果 
#注意!!!!概率密度图不能和 tsne一起画,因为plt会记录概率密度图的数据,导致画出来的TSNE 不准确
from sklearn.manifold import TSNE
tsne = TSNE()
tsne.fit_transform(data)  # 进行数据降维
# tsne.embedding_可以获得降维后的数据
print('tsne.embedding_: \n', tsne.embedding_)
tsn = pd.DataFrame(tsne.embedding_, index=data.index)  # 转换数据格式
print('tsne: \n', tsne)


# 不同类别用不同颜色和样式绘图
color_style = ['r.', 'go', 'b*']
for i in range(k):
    d = tsn[r[u'聚类类别'] == i]
    # dataframe格式的数据经过切片之后可以通过d[i]来得到第i列数据
    plt.plot(d[0], d[1], color_style[i], label='聚类' + str(i+1))
plt.legend()
plt.show()




Kmeans聚类原理及python实现代码

聚类结果第1类部分概率密度图:

聚类1人群的特征:first_inve_account 在-5000到8000之间,investment_to_now在 800-1400之间,其他维度同等分析方法

 

如有疑问,请及时联系哈!需要数据源的,可以私信我,我发你。