1. 语法
class sklearn.cluster.KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, precompute_distances='auto', verbose=0, random_state=None, copy_x=True, n_jobs=None, algorithm='auto')
参数说明:
- n_clusters=8 : K的值,我们想要将数据聚类成几类
- init='k-means++': 帮助你选择初始中心点的算法.
- n_init = 10: 有可能一次聚类效果不好(因为随机选择初始中心点,所以效果不稳定),重复用不同的随机数种子,聚类10次,从中找出效果最好的.
- max_iter=300 : 最大迭代次数.
- tol=0.0001 : 阈值,算法停止的阈值. 在迭代的过程当中, 组内距离平方和评估聚类效果,如果这个值在某次迭代过程中,下载不到这个tol的大小,那么就提前停止算法.
- random_state=None: 随机数种子
- verbose=0 : 模型的算法日志,数字越大代表日志越详细
- n_jobs=None: 使用cpu处理器个数,-1代表适用所有核心.
属性说明:
- cluster_centers_: 聚类最终的簇中心点.
- labels_: 每个样本被分到了哪一个簇中.
- inertia_: 评估指标,组内距离平方和.所有点到聚类中心点的距离平方和
- n_iter_ : 算法迭代次数
2. 算法实现
基本流程:导包 --> 导数据 --> 实例化 --> fit --> 画轮廓系数学习曲线 --> 找到最好K重新建模 --> 得到结果并加入源数据 --> 分析
2.1 生成聚类模拟数据
sklearn.datasets.make_blobs
参数说明:
- n_samples: 生成的数据样本个数
- n_features: 有多少个特征
- centers: 生成数据的中心点
- cluster_std: 聚类分布的标准差
- random_state : 随机数种子
函数返回值returns:
- X : 就是输入数据
- y : 标签
import numpy as np
import pandas as pd
import matplotlib.pylab as plt
from sklearn.datasets import make_blobs
# 生成四堆数据,所以四个中心点,四个标准差
X,y = make_blobs (n_samples = 1000,
n_features = 2,
centers = [ [-1,-1],[0,0],[1,1],[2,2] ],
cluster_std = [0.4,0.2,0.2,0.2],
random_state = 666)
plt.scatter(X[:,0] ,X[:,1], c=y);# 使用y标签进行颜色的映射
2.2 sklearn 实现Kmeans
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters = 2,random_state=666) #k = 2
kmeans.fit(X,y)
#查看属性
print("中心点:\n{}".format(kmeans.cluster_centers_))
print("组内平方和:\n{}".format(kmeans.inertia_))
print("迭代次数:\n{}".format(kmeans.n_iter_))
# 结果绘图
plt.scatter(X[:,0],X[:,1],c=kmeans.labels_)
plt.scatter(kmeans.cluster_centers_[:,0],kmeans.cluster_centers_[:,1],c = 'red',s = 100)
### 观察K变化之后,聚类的结果有什么不同,分别绘制出k取3,4,5,6的图形
plt.figure()
for k in range(3,7):
kmeans = KMeans(n_clusters = k,random_state=666)
kmeans.fit(X,y)
#绘图,子图模式需先建画板
plt.subplot(2,2,k-2)
plt.scatter(X[:,0],X[:,1],c=kmeans.labels_,label = "k = "+str(k))
plt.scatter(kmeans.cluster_centers_[:,0],kmeans.cluster_centers_[:,1],c = 'red',s = 100)
plt.legend()
2.3 通过学习曲线寻找最优K值
# 族值增加时,组内距离平方和必下降
scores = []
for k in range(2,10):
kmeans = KMeans(n_clusters = k,random_state=666)
kmeans.fit(X,y)
#将不同K的组内距离平方和保存
scores.append(kmeans.inertia_)
plt.plot(range(2,10),scores) # 4为最优参数,计算量和效果的妥协
# 再用K=4去重新建模fit就行了
3. 轮廓系数:评价聚类效果
SCi = (Bi - Ai)/max(Bi,AI)
- Ai:衡量一个点到 本 簇内其他点所有距离的 均值
- Bi:衡量一个点到 离他最近的其他 簇内所有点距离的 均值
- 一般来说,这个值如果超过0.1 ,聚类效果已经算是非常好了。
三种情况:
- 1.聚类效果很好,组内距离近,组外远,即:Bi>>Ai 则SCi = Bi/Bi 约等于1
- 2.聚类效果非常不好,组内距离远,组外近,还不如不聚类,即:Ai>>Bi 则SCi = -Ai/Ai 约等于 -1
- 3.SCi = 0 ,Ai = Bi 聚类无效果
3.1 代码实现流程
from sklearn.metrics import silhouette_score
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters = 3,random_state=666) #k = 3
kmeans.fit(X,y)
# 轮廓系数:
silhouette_score(X,kmeans.labels_)
3.2 用轮廓系数进行学习曲线调参
# 初级版
scores = []
for k in range(2,10):
kmeans = KMeans(n_clusters = k,random_state=666)
kmeans.fit(X,y)
#将不同K的组内距离平方和保存
scores.append(silhouette_score(X,kmeans.labels_))
plt.plot(range(2,10),scores) # 4为最优参数,计算量和效果的妥协
# 高级版
# 解决坐标轴刻度负号乱码
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams["font.family"] = 'Arial Unicode MS'
# 生成画布,设置大小
plt.figure(figsize = (10,12))
for k in range(2,8):
kmeans = KMeans(n_clusters = k,random_state=666)
kmeans.fit(X,y)
#将不同K的组内距离平方和保存
scores = silhouette_score(X,kmeans.labels_)
# 6次循环,6张子图,参数(i,j,k) i行j列的图,K为第K个
plt.subplot(3,2,k-1)
plt.scatter(X[:,0],X[:,1],c=kmeans.labels_)
plt.scatter(kmeans.cluster_centers_[:,0],kmeans.cluster_centers_[:,1],c = 'red',s = 100,label = "k = "+str(k)+"\n"+"轮廓系数 = "+str(round(scores,3)))
plt.text(0,-2,"轮廓系数 = "+str(round(scores,3))) #参数x,y,文字
plt.legend(loc="upper left",shadow=True,fancybox=True,fontsize=10 )
4. 真实数据集流程
基本流程:导包 --> 导数据 --> 实例化 --> fit --> 画轮廓系数学习曲线 --> 找到最好K重新建模 --> 得到结果并加入源数据 --> 分析
4.1 读入数据
mall_customer = pd.read_csv("Mall_Customers.csv")
mall_customer.head()
4.2 格式化并描述数据
# 把特征名称换成中文
d = {'CustomerID':'用户ID',
'Gender':'性别',
'Age':'年龄',
'Annual Income (k$)':'年收入',
'Spending Score (1-100)':'花销分数'}
mall_customer = mall_customer.rename(columns=d)
# 画图描述数据
import seaborn as sns
# 改变画图风格
plt.style.use('seaborn')
#mac电脑正常显示中文
plt.rcParams['font.family'] = ['Arial Unicode MS']
# 直方图
sns.distplot(mall_customer['年龄'],bins = 20)
sns.distplot(mall_customer['花销分数'] , bins= 20)
sns.distplot(mall_customer['年收入'] , bins= 20)
# 性别的分布
sns.countplot(x = '性别',data = mall_customer)
4.3 探索数据特征的性关系
# 自动帮你统计所有两两变量之间的关系,参数:数据[多列],reg是话回归线,看线性关系
sns.pairplot(mall_customer[['年龄','年收入','花销分数']],kind = 'reg')
plt.scatter(mall_customer['年收入'],mall_customer['花销分数'])
plt.xlabel('年收入')
plt.ylabel('花销分数')
4.4 用Kmeans聚类
from sklearn.metrics import silhouette_score
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters = 5,random_state=666) #k = 3
# 分隔X,mall_customer['年收入']是一维数据,转成二维才能输入
X1 = mall_customer[['年收入','花销分数']]
kmeans.fit(X1)
# 画图
plt.scatter(X1['年收入'],X1['花销分数'],c = kmeans.labels_,cmap='rainbow')
plt.scatter(kmeans.cluster_centers_[:,0], kmeans.cluster_centers_[:,1],
c = 'black',s = 100)
plt.title('k=3')
# 结果
kmeans.cluster_centers_ # 中心点
# 轮廓系数学习曲线
scores = []
for i in range(2,8): # 2-9
# 实例化
kmeans = KMeans(n_clusters=i , random_state=666)
kmeans.fit(X1)
scores.append(silhouette_score(X1 , kmeans.labels_) )
# 将曲线绘制出来
plt.plot(range(2,8) , scores); # 5对应的点最大
4.5 用三个特征聚类
# 非标准化数据情况:
X2 = mall_customer[['年收入','花销分数','年龄']]
scores = []
for i in range(2,10): # 2-9
# 实例化
kmeans = KMeans(n_clusters=i , random_state=666)
kmeans.fit(X2)
# 将轮廓系数和保存下来
scores.append(silhouette_score(X2 , kmeans.labels_) )
plt.plot(range(2,10) , scores); # 6对应的点,我们叫做拐点
# 标准化数据情况
from sklearn.preprocessing import MinMaxScaler
minmax = MinMaxScaler()
minmax.fit(X2)
X2_minmax = minmax.transform(X2)
scores = []
for i in range(2,15):
# 实例化
kmeans = KMeans(n_clusters=i , random_state=666)
kmeans.fit(X2_minmax)
# 将轮廓系数和保存下来
scores.append(silhouette_score(X2_minmax , kmeans.labels_) )
plt.plot(range(2,15) , scores); # 9最大,但对不标准化不明显,所以用不标准化的
4.6 确定聚合的6个簇,并添加到表
# 实例化
kmeans = KMeans(n_clusters=6 , random_state=666)
kmeans.fit(X2)
mall_customer['聚类结果'] = kmeans.labels_ #在此用的没标准化的数据
mall_customer.聚类结果.value_counts()
mall_customer[mall_customer['聚类结果'] == 3].describe()