聚类分析是一种基于中心的聚类算法(K 均值聚类),通过迭代,将样本分到 K 个类中,使得每个样本与其所属类的中心或均值的距离之和最小。与分层聚类等按照字段进行聚类的算法不同的是,快速聚类分析是按照样本进行聚类。
模型理论
K-Means 算法是一种无监督学习,同时也是基于划分的聚类算法,一般用欧式距离作为衡量数据对象间相似度的指标,相似度与数据对象间的距离成反比,相似度越大,距离越小。算法需要预先指定初始聚类数目 k 以及 k 个初始聚类中心,根据数据对象与聚类中心之间的相似度,不断更新聚类中心的位置,不断降低类簇的误差平方和(Sum of Squared Error,SSE),当 SSE 不再变化或目标函数收敛时,聚类结束,得到最终结果。
其核心思想是:
首先从数据集中随机选取 k 个初始聚类中心 Ci(1 ≤ i ≤ k) ,计算其余数据对象与聚类中心 Ci 的欧氏距离,找出离目标数据对象最近的聚类中心 Ci ,并将数据对象分配到聚类中心 Ci 所对应的簇中。然后计算每个簇中数据对象的平均值作为新的聚类中心,进行下一次迭代,直到聚类中心不再变化或达到最大的迭代次数停止。
代码
主要基于sklearn库来实现
from sklearn import cluster
from sklearn import metrics
np.set_printoptions(suppress=True)
class KMeans:
# 从原始数据中提取需要的变量数据
def getVars(self,var_list):
if type(var_list)==type(None):
return self.data.columns.tolist()
else:
return var_list
@staticmethod # 定类数据和定量数据分离
def processData(data:pd.DataFrame):
quan_data=data.select_dtypes(exclude='object')
qual_data=data.select_dtypes(include='object')
return {'quan':quan_data,'qual':qual_data}
@staticmethod # 生成定类数据量化规则
def generateRules(qual_arr):
qual_list=[]
for qual in qual_arr.columns.tolist():
qual_list.append(np.unique(qual_arr[qual]).tolist())
qual_rule_list=[]
for sub_qual_list in qual_list:
temp_rule={}
i=1
for qual in sub_qual_list:
temp_rule[qual]=i
i+=1
qual_rule_list.append(temp_rule)
res=qual_rule_list[0]
for i in range(1,len(qual_rule_list)):
res=dict(res,**qual_rule_list[i])
return res
# 确定定类数据量化规则
def getRules(self,rule):
if self.qual_data.columns.size==0:
return{}
elif type(rule)==type(None):
return self.generateRules(self.qual_data)
else:
return rule
# 根据规则将定类数据量化
def type2digit(self):
if len(self.rule)==0:
return self.var_data
else:
qual_data=self.qual_data.copy()
for key in self.rule.keys():
qual_data[qual_data==key]=self.rule[key]
return pd.merge(self.quan_data,qual_data,left_index=True,right_index=True)
def __init__(self,data:pd.DataFrame,n_clusters,var_list:list=None,rule:dict=None) -> None:
# 数据处理
self.data=data # 原始数据
self.var_list=self.getVars(var_list) # 变量列表
self.var_data=data[self.var_list] # 变量数据
self.sample_size=self.var_data.index.size # 样本数量
self.quan_data=self.processData(self.var_data)['quan'] # 定量数据
self.qual_data=self.processData(self.var_data)['qual'] # 定类数据
self.n_clusters=n_clusters # 聚类数量
self.rule=self.getRules(rule) # 定类量化规则
self.digited_data=self.type2digit() # 定类量化后数据
# 聚类分析
self.k_means=cluster.KMeans(n_clusters=self.n_clusters)
self.fit=self.k_means.fit_predict(self.digited_data[self.var_list])
# 轮廓系数评分
self.silhouette_score=metrics.silhouette_score(self.digited_data,self.fit)
# 卡林斯基-哈拉巴斯指数
self.calinski_harabasz_score=metrics.calinski_harabasz_score(self.digited_data,self.fit)
# 统计频数频率
def calFrequency(self):
freq=np.array([],dtype=np.float64)
for var in np.unique(self.k_means.labels_):
freq=np.insert(freq,freq.size,self.k_means.labels_[self.k_means.labels_==var].size)
rel_freq=freq/np.sum(freq)
data=np.c_[freq.reshape(freq.size,1),rel_freq.reshape(freq.size,1)]
return pd.DataFrame(data,columns=['频数','频率'])
# 标签数据
def labelData(self):
labels=pd.DataFrame(self.k_means.labels_.reshape(self.sample_size,1),columns=['聚类种类'])
return pd.merge(labels,self.var_data,left_index=True,right_index=True)
# 获取聚类中心
def getClusterCenters(self):
return pd.DataFrame(self.k_means.cluster_centers_,columns=self.var_list)
# 类别单独评分
def clusterRating(self):
silhouette=np.array([])
calinski=np.array([])
for var in self.var_list:
silhouette=np.insert(silhouette,silhouette.size,metrics.silhouette_score(self.digited_data[[var]],self.fit))
calinski=np.insert(calinski,calinski.size,metrics.calinski_harabasz_score(self.digited_data[[var]],self.fit))
data=np.c_[silhouette.reshape(silhouette.size,1),calinski.reshape(calinski.size,1)]
return pd.DataFrame(data,columns=['轮廓系数','卡林斯基-哈拉巴斯指数'],index=self.var_list)
def show(self):
print(f'n_clusters={self.n_clusters}的聚类分析结果如下:')
print(f'聚类结果汇总:总体样本量={self.sample_size}')
display(self.calFrequency())
print('聚类中心点:')
display(self.getClusterCenters())
print('聚类结果标注')
display(self.labelData())
print('聚类结果评估:轮廓系数范围[-1,1],越接近1结果越好,卡林斯基-哈拉巴斯指数越大结果越好')
print(f'总体轮廓系数={round(self.silhouette_score,6)},'+
f'总体卡林斯基-哈拉巴斯指数{round(self.calinski_harabasz_score,6)},各变量评分结果如下:')
display(self.clusterRating())
file='E:\DEV\python\math\data\聚类分析.xlsx'
data=pd.read_excel(file)
rule={'初中':2,'大学':4,'小学':1,'研究生':5,'高中':3}
human=KMeans(data,2,rule=rule)
human.show()
n_clusters=2的聚类分析结果如下: 聚类结果汇总:总体样本量=10000 频数 频率 0 5047.0 0.5047 1 4953.0 0.4953 聚类中心点: 收入 年龄 学历 0 15732.000396 38.264618 2.971853 1 7235.860747 38.131382 3.039758 聚类结果标注 聚类种类 收入 年龄 学历 0 1 6668 57 研究生 1 0 14658 60 研究生 2 1 6493 17 初中 3 0 12458 26 小学 4 0 12179 24 小学 ... ... ... ... ... 9995 0 17053 37 高中 9996 0 11713 19 研究生 9997 0 12012 64 高中 9998 1 3890 63 高中 9999 1 10890 34 研究生 10000 rows × 4 columns 聚类结果评估:轮廓系数范围[-1,1],越接近1结果越好,卡林斯基-哈拉巴斯指数越大结果越好 总体轮廓系数=0.630062,总体卡林斯基-哈拉巴斯指数30505.381932,各变量评分结果如下: 轮廓系数 卡林斯基-哈拉巴斯指数 收入 0.630101 30506.596478 年龄 -0.000117 0.208242 学历 0.000766 5.853331