摘要:在本案例中,我们使用人工智能技术的聚类算法去分析超市购物中心客户的一些基本数据,把客户分成不同的群体,供营销团队参考并相应地制定营销策略。

本文分享自华为云社区《基于K-means聚类算法进行客户人群分析》,作者:HWCloudAI 。

实验目标

  1. 掌握如何通过机器学习算法进行用户群体分析;
  2. 掌握如何使用pandas载入、查阅数据;
  3. 掌握如何调节K-means算法的参数,来控制不同的聚类中心。

案例内容介绍

在本案例中,我们使用人工智能技术的聚类算法去分析超市购物中心客户的一些基本数据,把客户分成不同的群体,供营销团队参考并相应地制定营销策略。

俗话说,“物以类聚,人以群分”,聚类算法其实就是将一些具有相同内在规律或属性的样本划分到一个类别中,算法的更多理论知识可参考此视频

我们使用的数据集是超市用户会员卡的基本数据以及根据购物行为得出的消费指数,总共有5个字段,解释如下:

  • CustomerID:客户ID
  • Gender:性别
  • Age:年龄
  • Annual Income (k$):年收入
  • Spending Score (1-100):消费指数

注意事项

  1. 如果你是第一次使用 JupyterLab,请查看《ModelAtrs JupyterLab使用指导》了解使用方法;
  2. 如果你在使用 JupyterLab 过程中碰到报错,请参考《ModelAtrs JupyterLab常见问题解决办法》尝试解决问题。

实验步骤

1. 准备源代码和数据

这步准备案例所需的源代码和数据,相关资源已经保存在OBS中,我们通过ModelArts SDK将资源下载到本地,并解压到当前目录下。解压后,当前目录包含data和src两个目录,分别存有数据集和源代码。

  1. import os
  2. from modelarts.session import Session
  3. if not os.path.exists('kmeans_customer_segmentation'):
  4. session = Session()
  5. session.download_data(bucket_path='modelarts-labs-bj4-v2/course/ai_in_action/2021/machine_learning/kmeans_customer_segmentation/kmeans_customer_segmentation.zip',
  6. path='./kmeans_customer_segmentation.zip')
  7. # 使用tar命令解压资源包
  8. os.system('unzip ./kmeans_customer_segmentation.zip')
  9. Successfully download file modelarts-labs-bj4/course/ai_in_action/2021/machine_learning/kmeans_customer_segmentation/kmeans_customer_segmentation.zip from OBS to local ./kmeans_customer_segmentation.zip

2. 导入工具库

matplotlib和seaborn是Python绘图工具,pandas和numpy是矩阵运算工具。

此段代码只是引入Python包,无回显(代码执行输出)。

  1. !pip install numpy==1.16.0
  2. import numpy as np # linear algebra
  3. import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
  4. import matplotlib.pyplot as plt
  5. import seaborn as sns
  6. from sklearn.cluster import KMeans
  7. import warnings
  8. import os
  9. warnings.filterwarnings("ignore")
  10. Requirement already satisfied: numpy==1.16.0 in /home/ma-user/anaconda3/envs/XGBoost-Sklearn/lib/python3.6/site-packages
  11. [33mYou are using pip version 9.0.1, however version 21.1.3 is available.
  12. You should consider upgrading via the 'pip install --upgrade pip' command.[0m

3. 数据读取

使用pandas.read_excel(filepath)方法读取notebook中的数据文件。

  • filepath:数据文件路径
  1. df = pd.read_csv('./kmeans_customer_segmentation/data/Mall_Customers.csv')

4. 展示样本数据

执行这段代码可以看到数据集的5个样本数据

  1. df.head()

<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }

  1. .dataframe tbody tr th {
  2. vertical-align: top;
  3. }
  4. .dataframe thead th {
  5. text-align: right;
  6. }

</style>

执行这段代码可以看到数据集的维度

  1. df.shape
  2. (200, 5)

5. 展示各个字段的统计值信息

调用pandas.DataFrame.describe方法,可以看到各个特征的统计信息,包括样本数、均值、标准差、最小值、1/4分位数、1/2分位数、3/4分位数和最大值。

  1. df.describe()

<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }

  1. .dataframe tbody tr th {
  2. vertical-align: top;
  3. }
  4. .dataframe thead th {
  5. text-align: right;
  6. }

</style>

6. 展示各个字段的数据类型

pandas.DataFrame.dtypes()方法可以展示各个字段的类型信息。

可以看到每个字段的类型信息。

  1. df.dtypes
  2. CustomerID int64
  3. Gender object
  4. Age int64
  5. Annual Income (k$) int64
  6. Spending Score (1-100) int64
  7. dtype: object

查看是否有数据缺失,如果有,则需要填补。

实验中使用的这份数据很完善,没有任何一个属性的值为null,因此统计下来,null值的数量都是0

  1. df.isnull().sum()
  2. CustomerID 0
  3. Gender 0
  4. Age 0
  5. Annual Income (k$) 0
  6. Spending Score (1-100) 0
  7. dtype: int64

7. 展示主要属性的数量分布

这段代码使用matplotlib绘制了数据中三个主要属性的统计直方图,包含年龄、收入、消费指数。

可以看到三张统计直方图,形状都与正态分布类似,说明数据量足够,数据抽样的分布也比较理想。

  1. plt.style.use('fivethirtyeight')
  2. plt.figure(1 , figsize = (15 , 6))
  3. n = 0
  4. for x in ['Age' , 'Annual Income (k$)' , 'Spending Score (1-100)']:
  5. n += 1
  6. plt.subplot(1 , 3 , n)
  7. plt.subplots_adjust(hspace =0.5 , wspace = 0.5)
  8. sns.distplot(df[x] , bins = 20)
  9. plt.title('Distplot of {}'.format(x))
  10. plt.show()

8. 展示男、女客户数量的分布

这段代码使用matplotlib绘制条状图,展示男、女样本数量的分布。

可以看到一张条状图。

  1. plt.figure(1 , figsize = (15 , 5))
  2. sns.countplot(y = 'Gender' , data = df)
  3. plt.show()

9. 观察不同属性之间的关系

展示任意两个属性之间的统计关系图。

此段代码执行后,会有9张统计图,展示了任意两个属性之间的统计关系。

  1. plt.figure(1 , figsize = (15 , 7))
  2. n = 0
  3. for x in ['Age' , 'Annual Income (k$)' , 'Spending Score (1-100)']:
  4. for y in ['Age' , 'Annual Income (k$)' , 'Spending Score (1-100)']:
  5. n += 1
  6. plt.subplot(3 , 3 , n)
  7. plt.subplots_adjust(hspace = 0.5 , wspace = 0.5)
  8. sns.regplot(x = x , y = y , data = df)
  9. plt.ylabel(y.split()[0]+' '+y.split()[1] if len(y.split()) > 1 else y )
  10. plt.show()

此段代码执行后,会有1张统计图,以性别为参照,展示了年龄和收入之间的对应统计关系

  1. plt.figure(1 , figsize = (15 , 6))
  2. for gender in ['Male' , 'Female']:
  3. plt.scatter(x = 'Age' , y = 'Annual Income (k$)' , data = df[df['Gender'] == gender] ,
  4. s = 200 , alpha = 0.5 , label = gender)
  5. plt.xlabel('Age'), plt.ylabel('Annual Income (k$)')
  6. plt.title('Age vs Annual Income w.r.t Gender')
  7. plt.legend()
  8. plt.show()

此段代码执行后,会有1张统计图,以性别为参照,展示了收入和消费指数之间的对应统计关系

  1. plt.figure(1 , figsize = (15 , 6))
  2. for gender in ['Male' , 'Female']:
  3. plt.scatter(x = 'Annual Income (k$)',y = 'Spending Score (1-100)' ,
  4. data = df[df['Gender'] == gender] ,s = 200 , alpha = 0.5 , label = gender)
  5. plt.xlabel('Annual Income (k$)'), plt.ylabel('Spending Score (1-100)')
  6. plt.title('Annual Income vs Spending Score w.r.t Gender')
  7. plt.legend()
  8. plt.show()

10. 观察不同性别的客户的数据分布

观察不同性别的客户的数据,在年龄、年收入、消费指数上的分布。

此段代码执行后,会有六幅boxplot图像。

  1. plt.figure(1 , figsize = (15 , 7))
  2. n = 0
  3. for cols in ['Age' , 'Annual Income (k$)' , 'Spending Score (1-100)']:
  4. n += 1
  5. plt.subplot(1 , 3 , n)
  6. plt.subplots_adjust(hspace = 0.5 , wspace = 0.5)
  7. sns.violinplot(x = cols , y = 'Gender' , data = df, palette='Blues')
  8. sns.swarmplot(x = cols , y = 'Gender' , data = df)
  9. plt.ylabel('Gender' if n == 1 else '')
  10. plt.title('Boxplots & Swarmplots' if n == 2 else '')
  11. plt.show()

11. 使用 K-means 对数据进行聚类

根据年龄和消费指数进行聚类和区分客户。

我们使用1-10个聚类中心进行聚类。(此段代码无输出)

  1. '''Age and spending Score'''
  2. X1 = df[['Age' , 'Spending Score (1-100)']].iloc[: , :].values
  3. inertia = []
  4. for n in range(1 , 11):
  5. algorithm = (KMeans(n_clusters = n ,init='k-means++', n_init = 10 ,max_iter=300,
  6. tol=0.0001, random_state= 111 , algorithm='elkan') )
  7. algorithm.fit(X1)
  8. inertia.append(algorithm.inertia_)

观察10次聚类的inertias,并以如下折线图进行统计。

inertias是K-Means模型对象的属性,它作为没有真实分类结果标签下的非监督式评估指标。表示样本到最近的聚类中心的距离总和。值越小越好,越小表示样本在类间的分布越集中。

可以看到,当聚类中心大于等于4之后,inertias的变化幅度显著缩小了。

  1. plt.figure(1 , figsize = (15 ,6))
  2. plt.plot(np.arange(1 , 11) , inertia , 'o')
  3. plt.plot(np.arange(1 , 11) , inertia , '-' , alpha = 0.5)
  4. plt.xlabel('Number of Clusters') , plt.ylabel('Inertia')
  5. plt.show()

我们使用4个聚类中心再次进行聚类。(此段代码无输出)

  1. algorithm = (KMeans(n_clusters = 4 ,init='k-means++', n_init = 10 ,max_iter=300,
  2. tol=0.0001, random_state= 111 , algorithm='elkan') )
  3. algorithm.fit(X1)
  4. labels1 = algorithm.labels_
  5. centroids1 = algorithm.cluster_centers_

我们把4个聚类中心的聚类结果,以下图进行展示。横坐标是年龄,纵坐标是消费指数,4个红点为4个聚类中心,4块不同颜色区域就是4个不同的用户群体。

  1. h = 0.02
  2. x_min, x_max = X1[:, 0].min() - 1, X1[:, 0].max() + 1
  3. y_min, y_max = X1[:, 1].min() - 1, X1[:, 1].max() + 1
  4. xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
  5. Z = algorithm.predict(np.c_[xx.ravel(), yy.ravel()])
  6. plt.figure(1 , figsize = (15 , 7) )
  7. plt.clf()
  8. Z = Z.reshape(xx.shape)
  9. plt.imshow(Z , interpolation='nearest',
  10. extent=(xx.min(), xx.max(), yy.min(), yy.max()),
  11. cmap = plt.cm.Pastel2, aspect = 'auto', origin='lower')
  12. plt.scatter( x = 'Age' ,y = 'Spending Score (1-100)' , data = df , c = labels1 ,
  13. s = 200 )
  14. plt.scatter(x = centroids1[: , 0] , y = centroids1[: , 1] , s = 300 , c = 'red' , alpha = 0.5)
  15. plt.ylabel('Spending Score (1-100)') , plt.xlabel('Age')
  16. plt.show()

根据年收入和消费指数进行聚类和区分客户。

我们使用1-10个聚类中心进行聚类。(此段代码无输出)

  1. '''Annual Income and spending Score'''
  2. X2 = df[['Annual Income (k$)' , 'Spending Score (1-100)']].iloc[: , :].values
  3. inertia = []
  4. for n in range(1 , 11):
  5. algorithm = (KMeans(n_clusters = n ,init='k-means++', n_init = 10 ,max_iter=300,
  6. tol=0.0001, random_state= 111 , algorithm='elkan') )
  7. algorithm.fit(X2)
  8. inertia.append(algorithm.inertia_)

观察10次聚类的inertias,并以如下折线图进行统计。

可以看到,当聚类中心大于等于5之后,inertias的变化幅度显著缩小了。

  1. plt.figure(1 , figsize = (15 ,6))
  2. plt.plot(np.arange(1 , 11) , inertia , 'o')
  3. plt.plot(np.arange(1 , 11) , inertia , '-' , alpha = 0.5)
  4. plt.xlabel('Number of Clusters') , plt.ylabel('Inertia')
  5. plt.show()

我们使用5个聚类中心再次进行聚类。(此段代码无输出)

  1. algorithm = (KMeans(n_clusters = 5 ,init='k-means++', n_init = 10 ,max_iter=300,
  2. tol=0.0001, random_state= 111 , algorithm='elkan') )
  3. algorithm.fit(X2)
  4. labels2 = algorithm.labels_
  5. centroids2 = algorithm.cluster_centers_

我们把5个聚类中心的聚类结果,以下图进行展示。横坐标是年收入,纵坐标是消费指数,5个红点为5个聚类中心,5块不同颜色区域就是5个不同的用户群体。

  1. h = 0.02
  2. x_min, x_max = X2[:, 0].min() - 1, X2[:, 0].max() + 1
  3. y_min, y_max = X2[:, 1].min() - 1, X2[:, 1].max() + 1
  4. xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
  5. Z2 = algorithm.predict(np.c_[xx.ravel(), yy.ravel()])
  6. plt.figure(1 , figsize = (15 , 7) )
  7. plt.clf()
  8. Z2 = Z2.reshape(xx.shape)
  9. plt.imshow(Z2 , interpolation='nearest',
  10. extent=(xx.min(), xx.max(), yy.min(), yy.max()),
  11. cmap = plt.cm.Pastel2, aspect = 'auto', origin='lower')
  12. plt.scatter( x = 'Annual Income (k$)' ,y = 'Spending Score (1-100)' , data = df , c = labels2 ,
  13. s = 200 )
  14. plt.scatter(x = centroids2[: , 0] , y = centroids2[: , 1] , s = 300 , c = 'red' , alpha = 0.5)
  15. plt.ylabel('Spending Score (1-100)') , plt.xlabel('Annual Income (k$)')
  16. fig = plt.gcf()
  17. if not os.path.exists('results'):
  18. os.mkdir('results') # 创建本地保存路径
  19. plt.savefig('results/clusters.png') # 保存结果文件至本地
  20. plt.show()

至此,本案例完成。

点击关注,第一时间了解华为云新鲜技术~

基于K-means聚类算法进行客户人群分析的更多相关文章

  1. 【机器学习】DBSCAN Algorithms基于密度的聚类算法

    一.算法思想: DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一个比较有代表性的基于密度的聚类算法.与划分和层 ...

  2. 简单易学的机器学习算法—基于密度的聚类算法DBSCAN

    简单易学的机器学习算法-基于密度的聚类算法DBSCAN 一.基于密度的聚类算法的概述 我想了解下基于密度的聚类算法,熟悉下基于密度的聚类算法与基于距离的聚类算法,如K-Means算法之间的区别.    ...

  3. 简单易学的机器学习算法——基于密度的聚类算法DBSCAN

    一.基于密度的聚类算法的概述     最近在Science上的一篇基于密度的聚类算法<Clustering by fast search and find of density peaks> ...

  4. k均值聚类算法原理和(TensorFlow)实现

    顾名思义,k均值聚类是一种对数据进行聚类的技术,即将数据分割成指定数量的几个类,揭示数据的内在性质及规律. 我们知道,在机器学习中,有三种不同的学习模式:监督学习.无监督学习和强化学习: 监督学习,也 ...

  5. K均值聚类算法

    k均值聚类算法(k-means clustering algorithm)是一种迭代求解的聚类分析算法,其步骤是随机选取K个对象作为初始的聚类中心,然后计算每个对象与各个种子聚类中心之间的距离,把每个 ...

  6. 机器学习实战---K均值聚类算法

    一:一般K均值聚类算法实现 (一)导入数据 import numpy as np import matplotlib.pyplot as plt def loadDataSet(filename): ...

  7. 基于改进人工蜂群算法的K均值聚类算法(附MATLAB版源代码)

    其实一直以来也没有准备在园子里发这样的文章,相对来说,算法改进放在园子里还是会稍稍显得格格不入.但是最近邮箱收到的几封邮件让我觉得有必要通过我的博客把过去做过的东西分享出去更给更多需要的人.从论文刊登 ...

  8. 基于K-means Clustering聚类算法对电商商户进行级别划分(含Octave仿真)

    在从事电商做频道运营时,每到关键时间节点,大促前,季度末等等,我们要做的一件事情就是品牌池打分,更新所有店铺的等级.例如,所以的商户分入SKA,KA,普通店铺,新店铺这4个级别,对于不同级别的商户,会 ...

  9. K均值聚类算法的MATLAB实现

    1.K-均值聚类法的概述    之前在参加数学建模的过程中用到过这种聚类方法,但是当时只是简单知道了在matlab中如何调用工具箱进行聚类,并不是特别清楚它的原理.最近因为在学模式识别,又重新接触了这 ...

  10. 5-Spark高级数据分析-第五章 基于K均值聚类的网络流量异常检测

    据我们所知,有‘已知的已知’,有些事,我们知道我们知道:我们也知道,有 ‘已知的未知’,也就是说,有些事,我们现在知道我们不知道.但是,同样存在‘不知的不知’——有些事,我们不知道我们不知道. 上一章 ...

随机推荐

  1. PTA 1126 Eulerian Path

    无向连通图,输出每个顶点的度并判断Eulerian.Semi-Eulerian和Non-Eulerian这3种情况,我们直接记录每个点所连接的点,这样直接得到它的度,然后利用深度优先和visit数组来 ...

  2. 华为云ubunbu部署.NetCore3.1项目(DDD商城)

    提前项目打包发布,文件传输工具Filezilla,注意是选择sftp协议,将publish文件传到/home文件夹下 第一步  .NetCoreSDK安装 微软官方的文档https://docs.mi ...

  3. BLS签名算法

    前言 [失踪人口回归 (*/ω\*)] 真的好久好久没有更新了,因为自己也还在找方向,但还是把新学的知识记录在博客里.今天要介绍的是BLS签名算法. 一.BLS签名算法简介 BLS签名算法[1]是由斯 ...

  4. 谣言检测(DUCK)《DUCK: Rumour Detection on Social Media by Modelling User and Comment Propagation Networks》

    论文信息 论文标题:DUCK: Rumour Detection on Social Media by Modelling User and Comment Propagation Networks论 ...

  5. 代码块及final关键字的使用

    1.代码块的作用:用来初始化类.对象 2.代码块如果有修饰的话,只能使用static. 3.分类:静态代码块 vs 非静态代码块 4.静态代码块 内部可以有输出语句 随着类的加载而执行,而且只执行一次 ...

  6. HTML+CSS基础知识(6)背景的设置、表格的设计、表单的设计和框架集

    文章目录 1.背景 1.1 代码 1.2 测试结果 2.背景练习 2.1 代码 2.2 测试结果 3.表格 3.1 代码 3.2 测试结果 4.练习 4.1 代码 4.2 测试结果 5.表单 5.1 ...

  7. go-zero docker-compose搭建课件服务(四):生成Dockerfile

    0.转载 go-zero docker-compose 搭建课件服务(四):生成Dockerfile并在docker-compose中启动 0.1源码地址 https://github.com/liu ...

  8. Droplet——一款轻量的Golang应用层框架

    Github地址 如标题所描述的,Droplet 是一个 轻量 的 中间层框架,何为中间层呢? 通常来说,我们的程序(注意这里我们仅仅讨论程序的范围,而非作为一个系统,因此这里不设计如 LB.Gate ...

  9. Eureka Server 实现在线扩容

    Eureka Server 实现在线扩容 作者:Grey 原文地址: 博客园:Eureka Server 实现在线扩容 CSDN:Eureka Server 实现在线扩容 需求 Eureka 是 Sp ...

  10. Golang 加密方法

    如果想直接使用我下列的库 可以直接go get 我的github go get -u github.com/hybpjx/InverseAlgorithm md5 加密--不可逆 MD5信息摘要算法是 ...