聚类算法.

聚类算法

1. 为什么学习聚类算法

在没有具体类别标签列或结果的前提下,我们还希望对已有的数据进行分类,这时候就需要使用聚类方法。

1.1 聚类方法案例引入

(1)两个人在话筒前面同时说话,录音后发现这两个人的声音混杂在一起。因此我们需要区分两个人的声音,这时候我们依靠声音的频谱不同对声音进行不同的区分,当然如果实现并不知道每个人声音的特点的话,那么需要利用人们的声音数据进行训练,这就可以利用监督学习方式来实现。

(2)我们试想下面场景:不同客户的有不同的特点和需求,针对每个客户的特点选定不同的销售策略。我们可以对每个客户选取不同的特征,之后进行静态分类,即聚类。

聚类在商业的应用中还有如下,按照不同主题对文档、音乐、电影进行分组,或基于常见的购买行为,发现有相同的兴趣爱好顾客,并在此构建推荐引擎。

聚类就是要挖掘数据蕴含的相似性的结构信息。

下面通过一个例子,简单的说明相似性的结构信息。对于下面的16张扑克牌,如何将他们分组呢?

总结:无论选择哪种划分方法,关键在于我们怎样定义并度量“相似性”。

1.2 聚类算法在现实中的应用

  • 用户画像,广告推荐,搜索引擎的流量推荐,恶意流量识别
  • 基于位置信息的商业推送,新闻聚类,筛选排序
  • 图像分割,降维,识别;离群点检测;信用卡异常消费;发掘相同功能的基因片段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qPcT8uT6-1634000523337)(./images/wpsj82Dyo.png)]

1.3 聚类算法的概念

聚类算法:

一种典型的无监督学习算法,主要用于将相似的样本自动归到一个类别中。

在聚类算法中根据样本之间的相似性,将样本划分到不同的类别中,对于不同的相似度计算方法,会得到不同的聚类结果,常用的相似度计算方法有欧式距离法。

1.4 聚类算法与分类算法最大的区别

聚类算法是无监督的学习算法,而分类算法属于监督的学习算法。

1.5 小结

  • 聚类的定义【了解】
  • 一种典型的无监督学习算法,
  • 主要用于将相似的样本自动归到一个类别中
  • 计算样本和样本之间的相似性,一般使用欧式距离

2. 小试牛刀-Sklearn实现KMeans聚类

2.1 api介绍

sklearn.cluster.KMeans(n_clusters=8)

参数: n_clusters:开始的聚类中心数量 整型,n_clusters=8,生成的聚类数,即产生的质心(centroids)数。

方法: estimator.fit(x) estimator.predict(x) estimator.fit_predict(x)计算聚类中心并预测每个样本属于哪个类别,相当于先调用fit(x),然后再调用predict(x)

2.2 案例

随机创建不同二维数据集作为训练集,并结合k-means算法将其聚类,你可以尝试分别聚类不同数量的簇,并观察聚类效果:

聚类参数n_cluster传值不同,得到的聚类结果不同

2.3 流程分析

2.4 代码实现

  1. 创建数据集
import matplotlib.pyplot as plt
from sklearn.datasets.samples_generator import make_blobs
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score 
# 创建数据集
# X为样本特征,Y为样本簇类别, 共1000个样本,每个样本2个特征,共4个簇,
# 簇中心在[-1,-1], [0,0],[1,1], [2,2], 簇方差分别为[0.4, 0.2, 0.2, 0.2]
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=9)

# 数据集可视化
plt.scatter(X[:, 0], X[:, 1], marker='o')
  1. 使用k-means进行聚类,并使用silhouette_score(轮廓系数)评估
model = KMeans(n_clusters=2, random_state=9)
y_pred = model.fit_predict(X)
# 分别尝试n_cluses=2\3\4,然后查看聚类效果
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()

# 用轮廓系数评估的聚类分数
silhouette_score(X, y_pred)
# 0.6435178953651656

2.5 小结

api:sklearn.cluster.KMeans(n_clusters=8)【知道】

参数:

  • n_clusters:开始的聚类中心数量

方法:

  • estimator.fit_predict(x)
  • 计算聚类中心并预测每个样本属于哪个类别,相当于先调用fit(x),然后再调用predict(x)

3. 聚类原理详解

3.1 距离的度量(相似性度量)

Euclidean Distance 定义

其他距离衡量:余弦值(cos), 相关度 (correlation), 曼哈顿距离 (Manhattan distance)

曼哈顿距离:纽约曼哈顿的街区比较平整,我们从P1起点到P2起点,首先横向跨越三个街区,在纵向跨越2个街区就达到P2点了。

3.2 Kmean算法原理

3.2.1 非监督中的Kmean算法

聚类(clustering) 属于非监督学习 (unsupervised learning),无类别标记(class label).

观察下图,相同类别的通过属性之间的相似性聚集在一起,算法中并未涉及类别标记的问题。

3.2.2 K-means算法详解

K-几个聚类中心,Mean-均值,每次迭代的时候使用均值方式迭代

  • K : 初始中心点个数(计划聚类数)
  • means:求中心点到其他数据点距离的平均值

Clustering 中的经典算法,数据挖掘十大经典算法之一

算法接受参数 k ;然后将事先输入的n个数据对象划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。

算法思想:

以空间中k个点为中心进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各聚类中心的值,直至得到最好的聚类结果

算法描述

(1)随机适当选择c个类的初始中心;

(2)在第k次迭代中,对任意一个样本,求其到c各中心的距离,将该样本归到距离最短的中心所在的类;

(3)利用均值等方法更新该类的中心值;

(4)对于所有的c个聚类中心,如果利用(2)(3)的迭代法更新后,聚类中心的值保持不变,则迭代结束,否则继续迭代。

**算法终止条件:**迭代次数/簇中心变化率/最小平方误差和SSE

算法核心步骤梳理:

计算距离—归类-----计算均值—距离----归类----均值----距离–…

(1)求解第i个样本xi到达第j个聚类中心的距离,选择j最小的值赋值给第i个样本的标记值。

(2)对于属于第j个样本的所有的xj求均值,作为第j个样本的新的聚类中心,聚类中心改变了,重新计算标记信息,标记变了重新计算距离。

算法流程巩固:

输入:k, data[n];

(1) 选择k个初始中心点,例如c[0]=data[0],…c[k-1]=data[k-1];

(2) 对于data[0]….data[n], 分别与c[0]…c[k-1]比较,假定与c[i]差值最少,就标记为i;

(3) 对于所有标记为i点,重新计算c[i]={所有标记为i的data[j]之和}/标记为i的个数;

(4) 重复(2)(3),直到所有c[i]值的变化小于给定阈值。

3.2.3 KMeans算法举例

  • 案例:
  • 1、随机设置K个特征空间内的点作为初始的聚类中心(本案例中设置p1和p2)

2、对于其他每个点计算到K个中心的距离,未知的点选择最近的一个聚类中心点作为标记类别

3、接着对着标记的聚类中心之后,重新计算出每个聚类的新中心点(平均值)

4、如果计算得出的新中心点与原中心点一样(质心不再移动),那么结束,否则重新进行第二步过程【经过判断,需要重复上述步骤,开始新一轮迭代】

5、当每次迭代结果不变时,认为算法收敛,聚类完成,K-Means一定会停下,不可能陷入一直选质心的过程。

3.2.4 K-Mean性能评价指标

3.2.4.1 SSE误差平方和

什么是SSE

举例:(下图中数据-0.2, 0.4, -0.8, 1.3, -0.7, 均为真实值和预测值的差)

在k-means中的应用:

公式各部分内容:

上图中: k=2

SSE图最终的结果,对图松散度的衡量.(eg: SSE(左图)

SSE随着聚类迭代,其值会越来越小,直到最后趋于稳定:

一种度量k-means算法的聚类效果的指标是误差平方和SSE(Sum of Squared-Error)。

符号 描述
x 样本
Ci 第i个簇
ci 簇Ci的质心(该簇的均值)
mi 第i个簇的样本个数
K 簇的个数

SSE表示数据样本与它所属的簇中心之间的距离(差异度)平方之和。直观的来说,SSE越小,表示数据点越接近它们的中心,聚类效果越好。因为对误差取了平方,更加重视那些远离中心的点。

3.2.4.2 肘部法

K值确定:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cOQ6uuLy-1634000523339)(./images/image-20210702103533262.png)]

(1)对于n个点的数据集,迭代计算k from 1 to n,每次聚类完成后计算每个点到其所属的簇中心的距离的平方和;

(2)平方和是会逐渐变小的,直到k==n时平方和为0,因为每个点都是它所在的簇中心本身。

(3)在这个平方和变化过程中,会出现一个拐点也即“肘”点,下降率突然变缓时即认为是最佳的k值

在决定什么时候停止训练时,肘形判据同样有效,数据通常有更多的噪音,在增加分类无法带来更多回报时,我们停止增加类别

3.2.4.3 轮廓系数

结合了聚类的凝聚度(Cohesion)和分离度(Separation),用于评估聚类的效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ei6KWyHg-1634000523340)(./images/轮廓系数.png)]

**目的:**内部距离最小化,外部距离最大化

计算样本i到同簇其他样本的平均距离ai,ai 越小样本i的簇内不相似度越小,说明样本i越应该被聚类到该簇。

计算样本i到最近簇Cj 的所有样本的平均距离bij,称样本i与最近簇Cj 的不相似度,定义为样本i的簇间不相似度:bi =min{bi1, bi2, …, bik},bi越大,说明样本i越不属于其他簇。

求出所有样本的轮廓系数后再求平均值就得到了平均轮廓系数

平均轮廓系数的取值范围为[-1,1],系数越大,聚类效果越好。

簇内样本的距离越近,簇间样本距离越远

3.2.4.4 总结

- sse【知道】

- 误差平方和的值越小越好

- 肘部法【知道】

- 下降率突然变缓时即认为是最佳的k值

- 轮廓系数(SC)【知道】

- 取值为[-1, 1],其值越大越好

3.2.5 K-Mean算法特点

优点:速度快,简单

对处理大数据集,该算法保持可伸缩性和高效率

当簇近似为高斯分布时,它的效果较好。

空间复杂度o(N),时间复杂度o(IKN)(N为样本点个数,K为中心点个数,I为迭代次数)

缺点:最终结果跟初始点选择相关,容易陷入局部最优,需直到k值

  • k均值算法中k是实现给定的,这个k值的选定是非常难估计的。
  • k均值的聚类算法需要不断地进行样本分类调整,不断地计算调整后的新的聚类中心,当数据量大的时候,算法开销很大。
  • k均值是求得局部最优解的算法,所以对于初始化时选取的k个聚类的中心比较敏感,不同点的中心选取策略可能带来不同的聚类结果。比如实际分类5类的情况却只进行了3均值的聚类。
  • 对噪声点和孤立点数据敏感。
  • KMeans一般是其他聚类方法的基础算法,如谱聚类。

4. 聚类分析案例

4.1 聚类分析案例1:顾客数据聚类分析

代码:

import pandas as pd
dataset = pd.read_csv('data/customers.csv')
dataset.head()

结果如下:

考虑最后两列作为分群依据

X = dataset.iloc[:, [3, 4]].values #全部行,第四第五列  Annual Income (k$) 和 Spending Score (1-100)
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters = 5, init = 'k-means++', random_state = 42) #k=5 
y_kmeans = kmeans.fit_predict(X)

#K-means与K-means++:
#原始K-means算法最开始随机选取数据集中K个点作为聚类中心,
#而K-means++按照如下的思想选取K个聚类中心:
#假设已经选取了n个初始聚类中心(0
#在选取第一个聚类中心(n=1)时同样通过随机的方法,防止陷入局部最优

画图展示聚类结果

plt.scatter(X[y_kmeans == 0, 0], X[y_kmeans == 0, 1], s = 100, c = 'red', label = 'Standard')
plt.scatter(X[y_kmeans == 1, 0], X[y_kmeans == 1, 1], s = 100, c = 'blue', label = 'Traditional')
plt.scatter(X[y_kmeans == 2, 0], X[y_kmeans == 2, 1], s = 100, c = 'green', label = 'Normal')
plt.scatter(X[y_kmeans == 3, 0], X[y_kmeans == 3, 1], s = 100, c = 'cyan', label = 'Youth')
plt.scatter(X[y_kmeans == 4, 0], X[y_kmeans == 4, 1], s = 100, c = 'magenta', label = 'TA')
# kmeans.cluster_centers_:聚类后每类的中心点
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s = 300, c = 'black', label = 'Centroids')
plt.title('Clusters of customers')
plt.xlabel('Annual Income (k$)')
plt.ylabel('Spending Score (1-100)')
plt.legend()
plt.show()

如下图:

评估聚类个数

import matplotlib.pyplot as plt
wcss = []
for i in range(1, 11): #循环使用不同k测试结果
  kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42)
  kmeans.fit(X)
  wcss.append(kmeans.inertia_) #inertia簇内误差平方和
  
plt.plot(range(1, 11), wcss)
plt.title('The Elbow Method')
plt.xlabel('Number of clusters')
plt.ylabel('WCSS')
plt.show()

结果如下:

结论:5个分群比较好

4.2 聚类时要注意的问题

K均值(K-Means)是聚类中最常用的方法之一,它基于点与点距离的相似度来计算最佳类别归属。但K均值在应用之前一定要注意两种数据异常:

1)数据的异常值。数据中的异常值能明显改变不同点之间的距离相似度,并且这种影响是非常显著的。因此基于距离相似度的判别模式下,异常值的处理必不可少。

2)数据的异常量纲。不同的维度和变量之间,如果存在数值规模或量纲的差异,那么在做距离之前需要先将变量归一化或标准化。例如,跳出率的数值分布区间是[0,1],订单金额可能是[0,10000000],而订单数量则是[0,1000]。如果没有归一化或标准化操作,那么相似度将主要受到订单金额的影响。

数据量过大的时候不适合使用k-means

K-Means在算法稳定性、效率和准确率(相对于真实标签的判别)上表现非常好,并且在应对大量数据时依然如此。它的算法时间复杂度上界为O(n * k * t),其中n是样本量、k是划分的聚类数、t是迭代次数。

当聚类数和迭代次数不变时,K均值的算法消耗时间只跟样本量有关,因此会呈线性增长趋势。

当真正面对海量数据时,使用K均值算法将面临严重的结果延迟,尤其是当K均值被用做实时性或准实时性的数据预处理、分析和建模时,这种瓶颈效应尤为明显。

针对K均值的这一问题,很多延伸算法出现了,MiniBatchKMeans就是其中一个典型代表。

MiniBatchKMeans使用了一个名为Mini Batch(分批处理)的方法计算数据点之间的距离。

MiniBatch的好处是计算过程中不必使用所有的数据样本,而是从不同类别的样本中抽取一部分样本(而非全部样本)作为代表参与聚类算法过程。

由于计算样本量少,所以会相应减少运行时间;但另一方面,由于是抽样方法,抽样样本很难完全代表整体样本的全部特征,因此会带来准确度的下降

经过对30000样本点分别使用K-Means 和 MiniBatchKMeans 进行聚类,对比之后运行时间 MiniBatchKMeans 是 K-Means的一半 (0.17 v.s. 0.36),但聚类结果差异性很小

**结论:**MiniBatchKMeans在基本保持了K-Means原有较高类别识别率的前提下,其计算效率的提升非常明显。因此,MiniBatchKMeans是一种能有效应对海量数据,尽量保持聚类准确性并且大幅度降低计算耗时的聚类算法

4.3 聚类分群案例2: 年龄与收入人群聚类

聚类分析案例

年龄与收入分群

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline

#加载数据
ageinc_df=pd.read_csv('data/ageinc.csv')
ageinc_df.info()
#两列数据,年龄与收入

查看数据基本统计信息

ageinc_df.describe()

如下图:

需要对数据进行标准化:

ageinc_df['z_income']=(ageinc_df['income']-ageinc_df['income'].mean())/ageinc_df['income'].std() #(收入-收入均值)/收入标准差
ageinc_df['z_age']=(ageinc_df['age']-ageinc_df['age'].mean())/ageinc_df['age'].std() #(年龄-年龄均值)/年龄标准差
ageinc_df.describe()

如下图:

初步进行数据可视化:

sns.scatterplot(x='income',y='age',data=ageinc_df)

如下图:

进行聚类分析:

#将群体分成3层
#用标准化的收入与年龄来拟合模型
from sklearn.cluster import KMeans
model=KMeans(n_clusters=3,random_state=10)
model.fit(ageinc_df[['z_income','z_age']])

#KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
#    n_clusters=3, n_init=10, n_jobs=1, precompute_distances='auto',
#    random_state=10, tol=0.0001, verbose=0)

#为用户打上标签
ageinc_df['cluster']=model.labels_
#查看用户的分群情况
ageinc_df.head(50)

如下图:

将分群结果可视化:

sns.scatterplot(x='age',y='income',hue='cluster',data=ageinc_df) #横轴为年龄,纵轴为收入,分类为用户分群标签

如下图:

将用户分为4层:

#将群体分成4层
#用标准化的收入与年龄来拟合模型
from sklearn.cluster import KMeans
model=KMeans(n_clusters=4,random_state=10)
model.fit(ageinc_df[['z_income','z_age']])

ageinc_df['cluster']=model.labels_
sns.scatterplot(x='age',y='income',hue='cluster',data=ageinc_df)
#横轴为年龄,纵轴为收入,分类为用户分群标签

可视化

将用户分为6层:

#将群体分成6层
#用标准化的收入与年龄来拟合模型
from sklearn.cluster import KMeans
model=KMeans(n_clusters=6,random_state=10)
model.fit(ageinc_df[['z_income','z_age']])

ageinc_df['cluster']=model.labels_
sns.scatterplot(x='age',y='income',hue='cluster',data=ageinc_df)
#横轴为年龄,纵轴为收入,分类为用户分群标签

如下图:

查看不同层用户的收入数据:

#使用groupby函数,将用户按照所在群分组,统计收入的数据
ageinc_df.groupby(['cluster'])['income'].describe()

如下图:

分析用户为4层的收入与年龄数据:

#将群体分成4层
#用标准化的收入与年龄来拟合模型
from sklearn.cluster import KMeans
model = KMeans(n_clusters=4,random_state=10)
model.fit(ageinc_df[['z_income','z_age']])

ageinc_df['cluster']=model.labels_
#收入
ageinc_df.groupby(['cluster'])['income'].describe()

如下图:

发现收入分为2档,一档0-8w,一档8-18w

#年龄
ageinc_df.groupby(['cluster'])['age'].describe()

如下图:

发现年龄分为2档,0和3为18岁-39岁中青年,1和2为40-60岁中老年

4.4 聚类分群案例2: airbnb客户分层

4.4.1 案例背景:

  • Airbnb在全球拥有广泛丰富的用户出行场景。自身在app和网页端,以及通过各种营销渠道会收集到非常全面的用户行为数据
  • 通过这些数据,锁定潜在的目标客群并指定相应的营销策略是Airbnb发展的重要基石

4.4.2 数据解释

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-McngTlIE-1634000523342)(./images/image-20210706111451900.png)]

4.4.3 数据分析思路

分析目标:通过数据,分析用户群体的核心特征

分析流程:数据概况分析->单变量分析->聚类分析

(1)数据概况分析

  • 数据行/列数量
  • 缺失值分布

(2)单变量分析

  • 数字型变量的描述指标
  • 类别型变量
  • 日期型变量处理

(3)聚类分析

  • 模型建立
  • 选择群数
  • 模型评估与优化

4.4.4 代码实战

  • 导入数据并查看数据情况
import pandas as pd
airbnb=pd.read_csv('data/airbnb.csv')
#查看数据类型
#变量类别:用户个人信息、用户与airbnb的关系、app使用语言、用户去的国家、用户下单渠道
#这里有2个日期变量,之后会进行操作
airbnb.info()

如下截图:

  • 用户数据具体情况
airbnb.head()

如下截图:

  • 单变量分析
airbnb.describe()

如下图:

  • 发现年龄最小是2最大是2014,属于数据异常,进行数据清洗,这里保留用户年龄在18-70岁之间的群体
airbnb=airbnb[airbnb['age']<=70]
airbnb=airbnb[airbnb['age']>=18]
airbnb.age.describe()

如下图:

  • 日期数据处理
#将注册日期转变为日期时间格式
airbnb['date_account_created']=pd.to_datetime(airbnb['date_account_created'])
airbnb.info()
#data_account_created变量格式从object转变为datetime64

如下图:

#将年份从中提取出来,将2019 -注册日期的年份,并生成一个新的变量year_since_account_created
airbnb['year_since_account_created']=airbnb['date_account_created'].apply(lambda x:2019-x.year)#计算注册至今(2019年)有几年
airbnb.year_since_account_created.describe()#注册时间最短的是5年,最长的是9年

如下图:

  • 计算用户第一次预定到2019年的时间
airbnb['date_first_booking']=pd.to_datetime(airbnb['date_first_booking'])
airbnb['year_since_first_booking']=airbnb['date_first_booking'].apply(lambda x:2019-x.year)
airbnb.year_since_first_booking.describe()#距离第一次预定时间最短的是4年,最长的是9年 

如下图:

  • 选择五个变量,作为分群的维度
airbnb_5=airbnb[['age','web','moweb','ios','android']]

#数据标准化,使用sklearn中预处理的scale
from sklearn.preprocessing import scale
x=pd.DataFrame(scale(airbnb_5))

#使用cluster建模
from sklearn.cluster import KMeans
#先尝试分为3类
model=KMeans(n_clusters=3,random_state=10)
model.fit(x)
#KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
#       n_clusters=3, n_init=10, n_jobs=None, precompute_distances='auto',
#       random_state=10, tol=0.0001, verbose=0)

#提取标签,查看分类结果
airbnb_5['cluster']=model.labels_
airbnb_5.head(10)

如下图:

  • 模型评估与优化
#使用groupby函数,评估各个变量维度的分群效果
airbnb_5.groupby(['cluster'])['age'].describe()

如下图:

代码:

airbnb_5.groupby(['cluster'])['ios'].describe()

如下图:

  • 使用silhouette score,评估模型效果
from sklearn.metrics import silhouette_score #调用sklearn的metrics库
x_cluster = model.fit_predict(x) #个体与群的距离
score = silhouette_score(x,x_cluster) #评分越高,个体与群越近;评分越低,个体与群越远
score
# 0.6304549142727769

# model.cluster_centers_获取每组的质心点
centers=pd.DataFrame(model.cluster_centers_)
centers.to_csv('center_3.csv')

#将群体分为5组
model=cluster.KMeans(n_clusters=5,random_state=10)
model.fit(x)
centers=pd.DataFrame(model.cluster_centers_)
centers.to_csv('center_5.csv')

  • 分三组之后的中心点数据
  • 分五组的中心点数据

你可能感兴趣的:(算法,机器学习,sklearn)