最关键的问题是其中k值的确定方式 手肘法: 核心指标:SSE(sum of the squared errors,误差平方和)
- Ci是第i个簇
- p是Ci中的样本点
- mi是Ci的质心(Ci中所有样本的均值)
- SSE是所有样本的聚类误差,代表了聚类效果的好坏。
手肘法核心思想
-
随着聚类数k的增大,样本划分会更加精细,每个簇的聚合程度会逐渐提高,那么误差平方和SSE自然会逐渐变小。 -
当k小于真实聚类数时,由于k的增大会大幅增加每个簇的聚合程度,故SSE的下降幅度会很大,而当k到达真实聚类数时,再增加k所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减,然后随着k值的继续增大而趋于平缓,也就是说SSE和k的关系图是一个手肘的形状,而这个肘部对应的k值就是数据的真实聚类数
import pandas as pd
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
df_features = pd.read_csv(r'C:\预处理后数据.csv',encoding='gbk')
'利用SSE选择k'
SSE = []
for k in range(1,9):
estimator = KMeans(n_clusters=k)
estimator.fit(df_features[['R','F','M']])
SSE.append(estimator.inertia_)
X = range(1,9)
plt.xlabel('k')
plt.ylabel('SSE')
plt.plot(X,SSE,'o-')
plt.show()
轮廓系数
但是问题就出在于如何通过图像确定k值? 直接通过肉眼判断是不可信的,因此选择使用轮廓系数 使用轮廓系数(silhouette coefficient)来确定,选择使系数较大所对应的k值
方法:
-
计算样本i到同簇其他样本的平均距离ai。ai 越小,说明样本i越应该被聚类到该簇。将ai 称为样本i的簇内不相似度。 簇C中所有样本的a i 均值称为簇C的簇不相似度。 -
计算样本i到其他某簇Cj 的所有样本的平均距离bij,称为样本i与簇Cj 的不相似度。定义为样本i的簇间不相似度:bi =min{bi1, bi2, …, bik} bi越大,说明样本i越不属于其他簇。 -
根据样本i的簇内不相似度a i 和簇间不相似度b i ,定义样本i的轮廓系数 -
判断: -
轮廓系数范围在[-1,1]之间。该值越大,越合理。 si接近1,则说明样本i聚类合理; si接近-1,则说明样本i更应该分类到另外的簇; 若si 近似为0,则说明样本i在两个簇的边界上。 -
所有样本的s i 的均值称为聚类结果的轮廓系数,是该聚类是否合理、有效的度量。 -
使用轮廓系数(silhouette coefficient)来确定,选择使系数较大所对应的k值 -
sklearn.metrics.silhouette_score sklearn中有对应的求轮廓系数的API
增加轮廓系数改进之后判断代码:
def cluster_para_est(train_x):
k_num = 50
sse = []
for k in range(1, k_num):
kmeans = KMeans(n_clusters=k)
kmeans.fit(train_x)
sse.append(kmeans.inertia_)
x = range(1, k_num)
plt.xlabel('K')
plt.ylabel('SSE')
plt.plot(x, sse, 'o-')
plt.show()
for idx in range(len(sse) - 1):
if sse[idx] - sse[idx + 1] <= 1:
print(idx + 1)
return idx + 1
|