一、什么是聚类?
1、聚类的定义
将所有观测值通过相似度评价方法分成不同的类。
2、应用场景
- 给商品做分组,为用户推荐他喜欢的商品所属分组内的其他商品
网易云音乐中,给曲库中的所有歌曲聚类。当用户喜欢了一首歌,会接着为他推荐该聚类中的其他歌曲。
淘宝猜你喜欢,当搜索“数据分析”后,会推荐数据分析分组中的其他商品。
- 给用户分组,为不同组的用户做个性化营销
明日之后中,为正在想加入营地的玩家推荐与其基本信息相似的营地。
二、常见的聚类算法
(一)k均值聚类
1、原理
距离采用欧氏距离计算。在二维空间中,两点之间的欧式距离就是三角形的斜边长,用勾股定理计算。
聚类的结果和随机选择的初始重心相关,为了避免初始重心选择过于临近,导致聚类效果不好,K-Means通常初始时要重复运行十几次甚至上百次。每次重复时,它会随机的从不同的位置开始初始化。最后把最小的成本函数对应的重心位置作为初始化位置。
2、成本函数
K-Means参数的最优解是以成本函数最小化为目标.
μk是第k个类的重心位置。
- 成本函数是各个类畸变程度(distortions)之和。
- 每个类的畸变程度:该类重心与其内部成员位置距离的平方和。
若类内部的成员彼此间越紧凑则类的畸变程度越小,反之,若类内部的成员彼此间越分散则类的畸变程度越大。
3、代码实现
import pandas as pd
from sklearn.model_selection import train_test_split,cross_val_score
from sklearn import datasets
rawfile = datasets.load_iris()
rawfile.feature_names # 获取自变量名称
rawfile.data # 获取自变量取值
rawfile.target # 获取因变量取值,0=setosa,1=versicolor,2=virginica
file = pd.DataFrame(data=rawfile.data, columns=rawfile.feature_names)
x = file
y = rawfile.target
建模
from sklearn.cluster import KMeans
model = KMeans(n_clusters = 3)
model.fit(x)
y_model = model.predict(x)
评估
# 方法一:畸变程度,越小越好(n_clusters可以=1)
from scipy.spatial.distance import cdist
sum(np.min(cdist(x, model.cluster_centers_, 'euclidean'), axis=1)) / x.shape[0] # 计算每个点距离其类别重心的欧氏距离的平均值
# 方法二:轮廓系数,越大越好(n_clusters不可以=1)
from sklearn import metrics
metrics.silhouette_score(x, model.labels_, metric='euclidean')
轮廓系数(Silhouette Coefficient) [ˌsɪluˈet][](javascript:;)是类的密集与分散程度的评价指标。它会随着类的规模增大而增大。彼此相距很远,本身很密集的类,其轮廓系数较大,彼此集中,本身很大的类,其轮廓系数较小。轮廓系数是通过所有样本计算出来的,计算每个样本分数的均值
超参数
n_clusters,表示聚类的数量.总和肘部法则和轮廓系数来看。
启发式方法来估计最优聚类数量,称为肘部法则(Elbow Method)。肘部法则会把不同值的成本函数值画出来。随着值的增大,平均畸变程度会减小;每个类包含的样本数会减少,于是样本离其重心会更近。但是,随着 值继续增大,平均畸变程度的改善效果会不断减低。 值增大过程中,畸变程度的改善效果下降幅度最大的位置对应的值就是肘部。
from scipy.spatial.distance import cdist
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\msyh.ttc", size=10)
meandistortions = []
for i in list(range(1,10)):
model = KMeans(n_clusters=i)
model.fit(x)
meandistortions.append(sum(np.min(cdist(x, model.cluster_centers_, 'euclidean'), axis=1)) / x.shape[0]) # 计算每个点距离其类别重心的欧氏距离的平均值
if i == 1:
continue
else:
print('i=',i,'轮廓系数是:',metrics.silhouette_score(x, model.labels_,metric='euclidean'))
plt.plot(list(range(1,10)), meandistortions, 'bx-')
plt.xlabel('n_clusters')
plt.ylabel('平均畸变程度',fontproperties=font)
plt.title('用肘部法则来确定最佳的K值',fontproperties=font)