基于K-means聚类算法进行客户人群分析

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

本文分享自华为云社区《基于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两个目录,分别存有数据集和源代码。

import os
from modelarts.session import Session
if not os.path.exists('kmeans_customer_segmentation'):
    session = Session()
 session.download_data(bucket_path='modelarts-labs-bj4-v2/course/ai_in_action/2021/machine_learning/kmeans_customer_segmentation/kmeans_customer_segmentation.zip',
                         path='./kmeans_customer_segmentation.zip')
 # 使用tar命令解压资源包
 os.system('unzip ./kmeans_customer_segmentation.zip')
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包,无回显(代码执行输出)。

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

3. 数据读取

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

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

4. 展示样本数据

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

df.head()

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

.dataframe tbody tr th {
    vertical-align: top;
}
.dataframe thead th {
    text-align: right;
}

</style>

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

df.shape
(200, 5)

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

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

df.describe()

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

.dataframe tbody tr th {
    vertical-align: top;
}
.dataframe thead th {
    text-align: right;
}

</style>

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

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

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

df.dtypes
CustomerID                 int64
Gender                    object
Age                        int64
Annual Income (k$)       int64
Spending Score (1-100)     int64
dtype: object

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

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

df.isnull().sum()
CustomerID 0
Gender                    0
Age                       0
Annual Income (k$) 0
Spending Score (1-100) 0
dtype: int64

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

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

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

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

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

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

可以看到一张条状图。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

至此,本案例完成。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/111962.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

做跨境电商,如何从同类产品中脱颖而出?

随便打开一个跨境电商平台&#xff0c;你会发现自己售卖的产品有那么多类似的选择&#xff0c;如何确保你的产品能被客户选择&#xff1f;怎样在一系列产品中脱颖而出&#xff1f; 不少卖家提到了&#xff0c;搞差异化竞争&#xff0c;这是跨境电商卖家常挂在嘴边的一个词&…

绝对肝货,超全的 MyBatis 动态代理原理讲解。

1.MyBatis简介 MyBatis是一个ORM工具&#xff0c;封装了JDBC的操作&#xff0c;简化业务编程&#xff1b; Mybatis在web工程中&#xff0c;与Spring集成&#xff0c;提供业务读写数据库的能力。 2.使用步骤 1.引入依赖 采用Maven包依赖管理&#xff0c;mybatis-3.5.5版本&…

MyBatis学习 | 动态SQL

文章目录一、简介二、if标签2.1 if标签的简单使用2.2 where标签2.3 trim标签&#xff08;了解&#xff09;三、choose标签 & set标签3.1 choose标签3.2 set标签四、foreach标签4.1 foreach标签的简单使用4.2 批量插入五、内置参数六、bind标签七、sql标签 & include标签…

2163. 删除元素后和的最小差值 堆解法解析

2163. 删除元素后和的最小差值 给你一个下标从 0 开始的整数数组 nums &#xff0c;它包含 3 * n 个元素。 你可以从 nums 中删除 恰好 n 个元素&#xff0c;剩下的 2 * n 个元素将会被分成两个相同大小的部分。 前面 n 个元素属于第一部分&#xff0c;它们的和记为 sumfirs…

Fabric.js 保存自定义属性

本文简介 点赞 关注 收藏 学会了 之前有些工友留言&#xff1a;在 fabric.js 中怎么保存元素的自定义属性&#xff1f; 比如&#xff0c;创建一个矩形&#xff0c;这个矩形有自己的 ID 属性&#xff0c;在执行序列化操作出来的结果却看不到 ID 属性了。 如何在序列化时输出…

项目实战之旅游网(三)后台用户管理(下)

目录 一.查询用户角色 二.修改用户角色 三.修改用户状态 一.查询用户角色 一个用户可以有多个角色&#xff0c;我们也可以给某个用户分配某些角色&#xff0c;所以我们还需要新建一个实体类&#xff08;这个实体类需要放到bean下&#xff0c;因为这个实体类和数据据库不是对…

【Effective_Objective-C_3接口与API设计】

文章目录前言15.用前缀避免命名空间冲突要点总结16.提供全能初始化方法全能初始化要点17.实现description方法description以字典形式输出descriptiondebugDescription要点18.尽量使用不可变对象要点19.使用清晰协调的命名方式方法命名类与协议命名要点20.为私有方法名加前缀21.…

人-机器人交互导论

【编者按&#xff1a;变主体性才是智能的真正厉害之处&#xff0c;能够设身处地地转换角色、角度、视角看待交互对象中的不确定性&#xff0c;并使用相应的同理同情共主观性机制机理进行处理&#xff0c;例如梅西过人中的真假变化。在个体/群体智能中的变主体性控制也是人机环境…

【圣诞节】飘雪圣诞树

一、前言 马上2023年的圣诞节&#x1f384;要到了&#xff0c;作为一个程序员&#xff0c;没什么可以送给大家的&#xff0c;就给大家画一个圣诞树&#x1f384;&#xff0c;作为礼物来送给大家吧。 二、创意名 明月当空飘雪圣诞树 三、效果展示 四、实现步骤 主要是利用three.…

详细设计说明书(GB8567——88)基于协同的在线表格forture-sheet

详细设计说明书 1引言 1.1编写目的 该文档在概要设计的基础上&#xff0c;进一步的细化系统结构&#xff0c;展示了软件结构的图标&#xff0c;物理设计、数据结构设计、及算法设计、详细的介绍了系统各个模块是如何实现的&#xff0c;包括涉及到的算法&#xff0c;逻辑流程…

【LeetCode每日一题:1754. 构造字典序最大的合并字符串~~~双指针+贪心算法】

题目描述 给你两个字符串 word1 和 word2 。你需要按下述方式构造一个新字符串 merge &#xff1a;如果 word1 或 word2 非空&#xff0c;选择 下面选项之一 继续操作&#xff1a; 如果 word1 非空&#xff0c;将 word1 中的第一个字符附加到 merge 的末尾&#xff0c;并将其…

《Unified Structure Generation for Universal Information Extraction》论文阅读

文章目录文章介绍文章方案用于统一结构编码的结构化抽取语言&#xff08;SEL&#xff09;用于可控IE结构生成的结构模式指导使用UIE生成预训练任务微调任务总结参考文章地址&#xff1a; https://arxiv.org/abs/2203.12277文章介绍 目前对于自然语言处理中的信息抽取任务如关系…

业聚医疗港交所上市:市值76亿港元 为钱永勋家族企业

雷递网 雷建平 12月23日血管介入器械公司――业聚医疗集团有限公司&#xff08;OrbusNeich Medical Group Limited&#xff09;&#xff08;简称“业聚医疗”&#xff0c;股票代码为&#xff1a;6929 &#xff09;今日在港交所上市。业聚医疗发行价为8.8港元&#xff0c;募资净…

SpringCloudGateway源码(四)限流组件

前言 如果不使用Alibaba Sentinel的网关流控规则&#xff0c; 是否可以选择使用SpringCloudGateway基于Redis的限流组件&#xff1f; 基于这个问题&#xff0c;笔者想了解一下scg自带限流组件的实现原理。 一、使用案例 1、pom 注意要加入redis-reactive依赖。 <depe…

OA系统遇到的问题

目录 一、开始时间与结束时间之差 二、弹出层的大小以及位置设置 2.1、高度设置body-style 2.2、位置设置dialogStyle 三、vue2安装引入Ant Design Vue 四、按钮控制盒子的显示与隐藏 五、表单生成器思想 5.1、点击左侧控件库生成中间的控件元素 5.2、点击中间的控件&…

Flink-状态编程的基本概念

文章目录Flink 中的状态1.1 有状态算子1.2 状态的管理1.3 状态的分类&#x1f48e;&#x1f48e;&#x1f48e;&#x1f48e;&#x1f48e; 更多资源链接&#xff0c;欢迎访问作者gitee仓库&#xff1a;https://gitee.com/fanggaolei/learning-notes-warehouse/tree/master Fli…

springcloud-gateway简介

目录 1. gateway简介 1.1 是什么 1.2 作用 1.3 主要特征 1.4 与zuul的主要区别 1.5 主要组件 1.6 架构图 2. 开发示例 2.1 创建一个gateway模块 2.2 与nacos结合使用 2.2.1 默认规则 2.2.2 通过配置文件配置路由 2.2.3 动态路由 1. gateway简介 1.1 是什么 SpringC…

一文带你深入理解【Java基础】· 网络编程(上)

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…

Kali Linux中安装IDLE的方法

1 IDLE简介 IDLE是Integrated Development and Learning Enviroment即集成开发和学习环境的简称&#xff0c;是Python的集成开发环境。在Kali Linux中&#xff0c;可以通过IDLE进行Python编程。 2 Kali Linux中安装IDLE 2.1 查看Kali Linux中是否安装IDLE 在Kali Linux终端…

WEB1.0起源:全球首个网站info.cern.ch

伯纳斯李&#xff08;图&#xff09;1990年创立第一个网站。 info.cern.ch是世上第一个网站&#xff0c;提供有关万维网的资料。 info.cern.ch这个网站依然运作如常。 英国科学家蒂姆伯纳斯-李 (Tim Berners-Lee) 于 1989 年在 CERN 工作期间发明了万维网 (WWW)。Web 最初的构思…