聚类算法

23 篇文章 1 订阅
21 篇文章 0 订阅

1. 简介

1.1 现实中的应用

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

1.2 定义

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

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

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

2. 分类

3.1 k_means

1. 原理

  1. 随机设置K个特征空间内的点作为初始的聚类中心
  2. 对于其他每个点计算到K个中心的距离,未知的点选择最近的一个聚类中心点作为标记类别
  3. 接着对着标记的聚类中心之后,重新计算出每个聚类的新中心点(平均值
  4. 如果计算得出的新中心点与原中心点一样(质心不再移动),那么结束,否则重新进行第二步过程

2. api使用

#- 参数:n_clusters:开始的聚类中心数量
sklearn.cluster.KMeans(n_clusters=8)

聚类算法api使用

  • 根据聚类结果计算ch值,进行评估模型

3. 优缺点

优点:

  1. 原理简单(靠近中心点),实现容易
  2. 聚类效果中上(依赖K的选择)

缺点:

  1. 对离群点,噪声敏感 (中心点易偏移)
  2. 结果不一定是全局最优,只能保证局部最优(与K的个数及初值选取有关)

4. 优化

4.1 Canopy
  • Canopy算法是获取最优K的算法,并不是进行聚类的算法。可以理解成是粗略聚类的过程
  • 根据算法得到k重新使用kmeans进行聚类操作

canopy获取最优k
缺点:

  • 算法中 T1、T2的确定问题 ,依旧可能落入局部最优解

优点:

  1. 有利于抗干扰。
  2. Canopy选择出来的每个Canopy的centerPoint作为K会更精确。
  3. 只是针对每个Canopy的内做Kmeans聚类,减少相似计算的数量。
4.2 K-means++
  • 原始kmeans算法最开始选择中心点时是随机选取(聚类结果和初始中心点相关)
  • kmeans++目的,让选择的质心尽可能的分散

k-means++

4.3 二分k-means

实现流程:

  1. 所有点作为一个簇
  2. 将该簇一分为二
  3. 选择能最大限度降低聚类代价函数(也就是误差平方和)的簇划分为两个簇。
  4. 以此进行下去,直到簇的数目等于用户给定的数目k为止。
4.4 k-medoids
1. 简介
  • K-medoids和K-means是有区别的 不一样的地方在于中心点的选取
  • kmeans算法是对类别内部进行x y求平均得到新的中心点
  • K-medoids中,将从当前cluster 中选取到其他所有(当前cluster中的)点的距离之和最小的点作为中心点。
2. 算法流程
  1. 总体n个样本点中任意选取k个点作为medoids
  2. 按照与medoids最近的原则,将剩余的n-k个点分配到当前最佳的medoids代表的类中
  3. 对于第i个类中除对应medoids点外的所有其他点,按顺序计算当其为新的medoids时,代价函数的值,遍历所有可能,选取代价函数最小时对应的点作为新的medoids
  4. 重复2-3的过程,直到所有的medoids点不再发生变化或已达到设定的最大迭代次数
  5. 产出最终确定的k个类
3. 缺点
  • k-medoids只能对小样本起作用,样本大,速度就太慢了
  • 当样本多的时候,少数几个噪音对k-means的质心影响也没有想象中的那么重
  • 所以k-means的应用明显比k-medoids多。

3. 模型评估

3.1 SSE

  • 误差平方和SSE(Sum of the Squared Errors):计算k取某个值(2)时的误差值

聚类算法模型评估的误差平方和SSE

3.2 “肘”方法

  • 对于n个点的数据集,迭代计算k from 1 to n,分别计算误差值
  • 下降率突然变缓时即认为是最佳的k值

3.3 轮廓系数法

  • 结合了聚类的凝聚度(Cohesion)和分离度(Separation)

轮廓系数法

3.4 CH系数

  • 类别内部数据的协方差越小越好,类别之间的协方差越大越好

4. 应用

4.1 顾客数据

1. 思路分析

1 加载数据

2 两列作为分群依据

​	构造kmeans模型进行聚类

3 画图展示聚类结果

4 评估聚类个数 通过肘方法

聚类时要注意的问题

K均值在应用之前一定要注意两种数据异常 数据的异常值。数据的异常量纲。

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

 MiniBatchKMeans就是其中一个典型代表。

2. 实现

import pandas as pd
dataset = pd.read_csv('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<K),则在选取第n+1个聚类中心时:距离当前n个聚类中心越远的点会有更高的概率被选为第n+1个聚类中心。
  #在选取第一个聚类中心(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')
  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个分群比较好

3. 聚类时要注意的问题

  • 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.2 年龄与收入分群

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
#加载数据
ageinc_df=pd.read_csv('ageinc.csv')
ageinc_df.info()
#两列数据,年龄与收入
  • 输出显示
RangeIndex: 1000 entries, 0 to 999
Data columns (total 2 columns):
income    1000 non-null int64
age       1000 non-null int64
dtypes: int64(2)
memory usage: 15.7 KB
  • 查看数据基本统计信息
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)

数据可视化

  • 进行聚类分析
from sklearn import cluster
model=cluster.KMeans(n_clusters=3,random_state=10)
model.fit(ageinc_df[['z_income','z_age']])
#导入sklearn中的cluster
#将群体分成3层
#用标准化的收入与年龄来拟合模型
#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层
from sklearn import cluster
model=cluster.KMeans(n_clusters=4,random_state=10)
model.fit(ageinc_df[['z_income','z_age']])
#导入sklearn中的cluster
#将群体分成4层
#用标准化的收入与年龄来拟合模型
ageinc_df['cluster']=model.labels_
sns.scatterplot(x='age',y='income',hue='cluster',data=ageinc_df)
#横轴为年龄,纵轴为收入,分类为用户分群标签
  • 可视化

数据可视化

  • 将用户分为6层
from sklearn import cluster
model=cluster.KMeans(n_clusters=6,random_state=10)
model.fit(ageinc_df[['z_income','z_age']])
#导入sklearn中的cluster
#将群体分成6层
#用标准化的收入与年龄来拟合模型
ageinc_df['cluster']=model.labels_
sns.scatterplot(x='age',y='income',hue='cluster',data=ageinc_df)
#横轴为年龄,纵轴为收入,分类为用户分群标签

数据可视化

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

查看数据

  • 分析用户为4层的收入与年龄数据
from sklearn import cluster
model=cluster.KMeans(n_clusters=4,random_state=10)
model.fit(ageinc_df[['z_income','z_age']])
#导入sklearn中的cluster
#将群体分成4层
#用标准化的收入与年龄来拟合模型
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.3 airbnb客户分层

1. 案例背景

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

2. 数据解释

数据解释

3. 数据分析思路

  • 分析目标:通过数据,分析用户群体的核心特征
  • 分析流程:数据概况分析->单变量分析-> 聚类分析
    • 数据概况分析
      • 数据行/列数量
      • 缺失值分布
    • 单变量分析
      • 数字型变量的描述指标
      • 类别型变量
      • 日期型变量处理
    • 聚类分析
      • 模型建立
      • 选择群数
      • 模型评估与优化

4. 实现

- Airbnb在全球拥有广泛丰富的用户出行场景。自身在app和网页端,以及通过各种营销渠道会收集到非常全面的用户行为数据

数据分析思路

- 分析目标:通过数据,分析用户群体的核心特征
- 分析流程:数据概况分析->单变量分析->聚类分析

- 数据概况分析
  - 数据行/列数量
  - 缺失值分布
- 单变量分析
  - 数字型变量的描述指标
  - 类别型变量
  - 日期型变量处理
- 聚类分析
  - 模型建立
  - 选择群数
  - 模型评估与优化
  • 导入数据并查看数据情况
import pandas as pd
airbnb=pd.read_csv('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年

查看数据

  • 将类别型型转化成哑变量(gender)
airbnb=pd.get_dummies(airbnb)
airbnb.info()

数据预处理

  • 删除两个日期变量,可以根据数据格式来进行drop
airbnb.drop(airbnb.select_dtypes(['datetime64']),inplace=True,axis=1)
  • 选择五个变量,作为分群的维度
airbnb_5=airbnb[['age','web','moweb','ios','android']]
#数据标准化,使用sklearn中预处理的scale
from sklearn.preprocessing import scale
x=pd.DataFrame(scale(airbnb_5))
#使用cluster建模
from sklearn import cluster
#先尝试分为3类
model=cluster.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 import metrics#调用sklearn的metrics库
x_cluster=model.fit_predict(x)#个体与群的距离
score=metrics.silhouette_score(x,x_cluster)#评分越高,个体与群越近;评分越低,个体与群越远
print(score)
0.6304549142727769
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')
  • 分三组之后的中心点数据

在这里插入图片描述

  • 分五组的中心点数据

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值