Python数据分析案例51——基于K均值的客户聚类分析可视化

案例背景

本次案例带来的是最经典的K均值聚类,对客户进行划分类别的分析,其特点是丰富的可视化过程。这个经典的小案例用来学习或者课程作业在合适不过了。


数据介绍

数据集如下:

        

客户的编码,性别,年龄,年收入,还有一个花费分,可能就是消费的越多这个分越高。

下面我们会对这些维度进行分析和可视化,然后进行K均值聚类。主要有这些步骤:

  • 导入库。
  • 数据探索。
  • 数据可视化。
  • 使用 K-Means 进行聚类。
  • 集群的选择。
  • 绘制聚类边界和聚类。
  • 聚类的 3D 图

下面开始,当然,需要本期数据案例和全部代码文件的同学还是可以参考:客户聚类​​​​​​​


代码实现

导入库

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 
import plotly as py
import plotly.graph_objs as go
from sklearn.cluster import KMeans
import warnings
import os
warnings.filterwarnings("ignore")#print(os.listdir("../input"))

数据探索

读取数据

df = pd.read_csv('Mall_Customers.csv')
df.head()

查看数据形状

df.shape

200个样本

描述性统计

df.describe()

查看数据类型

df.dtypes

可以看到编号,年龄,收入,消费分都是数值型数据,年龄是类别变量。

查看是否有空值。

df.isnull().sum()

没有缺失值。


数据可视化

设置一下画图风格

plt.style.use('fivethirtyeight')

直方图

画年龄,收入,消费的直方图

plt.figure(1 , figsize = (15 , 6))
n = 0 
for x in ['Age' , 'Annual Income (k$)' , 'Spending Score (1-100)']:n += 1plt.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()

可以看到分布都还很正常,类似正态,没有极端分布。

性别统计柱状图

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

女性比男性多。

画出年龄,收入,花费等关系

画出他们两两的散点图和回归线

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 += 1plt.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()

可以看到年龄和消费是负相关,年龄和收入没有明显的关系。

不同性别的收入

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()

性别和收入感觉也没太多关系,

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()

性别和消费感觉也没太多关系,

按性别划分的年龄、年收入和支出得分的值分布

画出他们的小提琴图

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 = 'vlag')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()

该可视化展示了男性和女性两种性别的年龄、年收入和支出得分分布。每个子图都展示了箱线图和群图的组合,可提供有关数据分布和各个数据点的详细见解。

该可视化展示了男性和女性两种性别的年龄、年收入和支出得分分布。每个子图都展示了箱线图和群图的组合,可提供有关数据分布和各个数据点的详细见解。

分析

年龄
  • 男性:
    • 男性的年龄分布范围似乎很广,大约从 20 岁到 70 岁。
    • 较低年龄组的密度较高,表明较低年龄段的男性较多。
  • 女性:
    • 女性的年龄分布略微偏向年轻年龄组,在 20-40 岁左右的年龄段达到明显的峰值。
    • 与男性相比,女性的传播更集中在较低年龄段。
年收入
  • 男性:
    • 男性的年收入分布很广,从大约 20,000 美元到 140,000 美元不等。
    • 收入在 50,000 至 80,000 美元之间的男性密度明显较高。
  • 女性:
    • 女性的年收入范围也较大,但分布相对于男性来说稍微集中一些。
    • 密度较高,在 40,000 美元到 80,000 美元左右。
消费评分
  • 男性:
    • 男性的消费分数分布广泛,从 1 到 100。
    • 低端和高端都有峰值,表明低消费者和高消费者聚集。
  • 女性:
    • 雌性的分布与雄性相似,但中间范围的密度略高(约 50)。
    • 这表明女性的消费模式更加均衡。
重要见解
  1. 年龄分布:
    • 两种性别的人口峰值都较年轻,但男性的年龄范围更广,而女性则更多地集中在较低的年龄段。
  2. 收入分配:
    • 男性的收入范围更加多样化,而女性的收入则集中在特定范围内(40,000 美元至 80,000 美元)。
  3. 消费分数:
    • 两种性别的消费分数差异很大,男性的两端都有明显的峰值,这表明消费模式更加独特。
结论

可视化结果详细比较了男性和女性的年龄、年收入和支出分数分布。它强调,虽然两种性别有一些相似之处,但这些变量的集中度和分散度存在显著差异。男性在年龄和收入方面的分布往往更广泛,而女性则在特定范围内表现出更高的集中度。支出分数表明两种性别的消费行为各不相同,男性表现出更多的极端值。


使用 K- 均值进行聚类

1.使用年龄和消费评分进行聚类和分类客户

首先k均值我们得需要考虑K的数量。所以我们遍历1-11类,查看不同类别下的平方和距离,找一个合适值。

'''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_)

 可视化不同K,也就是聚类数量和平方和损失的值。

选择基于惯性的 N 个聚类(质心和数据点之间的平方距离,应更小

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()

可以看到k从1到4损失下降的较多,4之后就下降的比较少,所以我们选择K=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_

 聚类中心存在centroids1里面

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()

可以清楚的看到每个类别的区间,中心,和分布情况。

2.使用年收入和支出得分进行细分

现在换个2个变量来聚类,使用年收入和支出得分进行聚类和分类

一样的,寻找最优的聚类个数

'''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_)

可视化

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()

这一次k=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_
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$)')
plt.show()

可视化,很清楚的看到每个类别的分布,中心,和区间。

3.使用年龄、年收入和支出分数进行细分

上面是用2个变量,现在吧全部三个变量都用上进行聚类

一样的,先找K的最优取值。

X3 = df[['Age' , '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(X3)inertia.append(algorithm.inertia_)

可视化

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()

这次K=6的时候比较合适

algorithm = (KMeans(n_clusters = 6 ,init='k-means++', n_init = 10 ,max_iter=300, tol=0.0001,  random_state= 111  , algorithm='elkan') )
algorithm.fit(X3)
labels3 = algorithm.labels_
centroids3 = algorithm.cluster_centers_

三维的图可视化就麻烦点,就用plotly来画

df['label3'] =  labels3
trace1 = go.Scatter3d(x= df['Age'],y= df['Spending Score (1-100)'],z= df['Annual Income (k$)'],mode='markers',marker=dict(color = df['label3'], size= 20,line=dict(color= df['label3'],width= 12),opacity=0.8)
)
data = [trace1]
layout = go.Layout(
#     margin=dict(
#         l=0,
#         r=0,
#         b=0,
#         t=0
#     )title= 'Clusters',scene = dict(xaxis = dict(title  = 'Age'),yaxis = dict(title  = 'Spending Score'),zaxis = dict(title  = 'Annual Income'))
)
fig = go.Figure(data=data, layout=layout)
py.offline.iplot(fig)

这个图在jupyter里面是可以进行拖拽和放大的,很方便的观察不同客户的特点。

可以看到不同类别的客户特点,来以此进行定制化策略。


创作不易,看官觉得写得还不错的话点个关注和赞吧,本人会持续更新python数据分析领域的代码文章~(需要定制类似的代码可私信)

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

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

相关文章

Vue2-集成路由Vue Router介绍与使用

文章目录 路由(Vue2)1. SPA 与前端路由2. vue-router基本使用创建路由组件声明路由链接和占位标签创建路由模块挂载路由模块 3. vue-router进阶路由重定向嵌套路由动态路由编程式导航导航守卫 本篇小结 更多相关内容可查看 路由(Vue2&#xf…

安全防御----防火墙综合实验2

安全防御----防火墙综合实验2 一、题目 二、实验要求: 1,DMZ区内的服务器,办公区仅能在办公时间内(9:00 - 18:00)可以访问,生产区的设备全天可以访问. 2,生产区不允许访…

雷赛运动控制卡编程(1)

一、运动控制卡选择 电气常用知识-CSDN博客 如下旋转控制卡 DMC3800八轴高性能点位卡 - 东莞市雅恰达机电有限公司 轴少的时候选择脉冲系列卡 轴多的话就选总线型系列控制卡 样品 架构: 二、 添加文件 dll 添加接口文件 【最全,带注释版】雷赛运动…

OpenCV中使用Canny算法在图像中查找边缘

操作系统:ubuntu22.04OpenCV版本:OpenCV4.9IDE:Visual Studio Code编程语言:C11 算法描述 Canny算法是一种广泛应用于计算机视觉和图像处理领域中的边缘检测算法。它由John F. Canny在1986年提出,旨在寻找给定噪声条件下的最佳边…

Python+wxauto=微信自动化?

Pythonwxauto微信自动化? 一、wxauto库简介 1.什么是wxauto库 wxauto是一个基于UIAutomation的开源Python微信自动化库。它旨在帮助用户通过编写Python脚本,轻松实现对微信客户端的自动化操作,从而提升效率并满足个性化需求。这一工具的出现&…

详细分析Sql Server中的declare基本知识

目录 前言1. 基本知识2. Demo3. 拓展Mysql4. 彩蛋 前言 实战探讨主要来源于触发器的Demo 1. 基本知识 DECLARE 语句用于声明变量 声明的变量可以用于存储临时数据,并在 SQL 查询中多次引用 声明变量:使用 DECLARE 语句声明一个或多个变量变量命名&a…

SpringBoot整合JAX-RS接口

目录 二、创建RESTful资源 三、注册JAX-RS资源 四、修改配置等信息 五、启动SpringBoot程序、访问服务 六、遇到的问题 七、与feign进行配合使用 1、接口定义 2、接口实现 3、注册资源 4、调用方web服务实现,跟注入普通服务一样 5、启动两个服务&#xff…

html5——表单

目录 表单基本结构 表单标签 常用表单元素 文本框 密码框 邮箱 单选按钮 复选框 文件域 隐藏域 列表框 多行文本域 lable标签 表单按钮 常用表单属性 只读与禁用 placeholder required pattern autofocus autocomplete 用于指定表单是否有自动完…

NoSQL之redis的配置与优化

一、redis数据库的基础介绍与对比 Redis(RemoteDictionaryServer,远程字典型)是一个开源的、使用C语言编写的NoSQL数据库。Redis 基于内存运行并支持持久化,采用 key-value(键值对)的存储形式,是目前分布式架构中不可或缺的一环。 1.非关系…

百日筑基第二十天-一头扎进消息队列3-RabbitMQ

百日筑基第二十天-一头扎进消息队列3-RabbitMQ 如上图所示,RabbitMQ 由 Producer、Broker、Consumer 三个大模块组成。生产者将数据发送到 Broker,Broker 接收到数据后,将数据存储到对应的 Queue 里面,消费者从不同的 Queue 消费数…

我的智能辅助大师-办公小浣熊

一、基本介绍 随着2022年ChatGPT为代表的AI工具对互联网领域进行第一次冲击后,作为一名对编程领域涉足不算特别深的一名程序员,对AI大模型的接触也真的不能算少了,这是时代的必然趋势。在此之前也曾接触过很多的AI工具,他们都能在…

【Vscode】显示多个文件 打开多个文件时实现标签栏多行显示

Vscode显示多个文件&VSCode打开多个文件时实现标签栏多行显示 写在最前面一、解决打开文件的时候只显示一个tab的办法解决办法如下: 二、文件标签栏多行显示设置步骤: 🌈你好呀!我是 是Yu欸 🌌 2024每日百字篆刻时…

电脑维护全攻略:让你的“战友”焕发新生

目录 电脑维护全攻略:让你的“战友”焕发新生 引言 方向一:了解你的“战友” 1.1 电脑品牌与型号的选择 1.2 电脑硬件配置的重要性 1.3 电脑软件配置的重要性 方向二:日常维护措施 2.1 定期清理与优化 2.2 保持良好的上网习惯 2.3 …

微服务-注册中心

一. 分布式系统架构与微服务 分布式系统架构和微服务是现代软件开发中常见的两种概念,它们通常结合使用来构建灵活、可扩展和高效的应用程序。 分布式系统架构: 分布式系统架构是指将一个单一的应用程序或服务拆分成多个独立的部分,这些部分…

邮箱表单系统源码

邮箱表单简介 我们的邮箱表单系统是一个简洁高效的工具,旨在为用户提供一种便捷的方式来提交他们的邮箱地址。该系统可以用于订阅新闻通讯、注册活动、获取用户反馈等多种场景。 功能特点: 用户友好的界面: 表单设计简洁直观,用…

t-SNE降维可视化并生成excel文件使用其他画图软件美化

t-sne t-SNE(t-分布随机邻域嵌入,t-distributed Stochastic Neighbor Embedding)是由 Laurens van der Maaten 和 Geoffrey Hinton 于 2008 年提出的一种非线性降维技术。它特别适合用于高维数据的可视化。t-SNE 的主要目标是将高维数据映射…

修改vscode的字体为等宽字符

在文件——首选项——设置 中 搜索 Editor: Font Family 将内容改为下面的 Consolas, Courier New, monospace 之后重启Vscode就行了

初步探究Rust生态与图形界面编程

引言 Rust作为一种现代的、安全的系统编程语言,自2010年问世以来,逐渐在开发社区中崭露头角。它的内存安全保证、并发处理能力、以及无需垃圾回收机制的高性能特性,使得它成为了开发系统工具、网络服务、以及嵌入式系统的热门选择。然而&…

(五十三)第 8 章 动态存储管理(伙伴系统)

1. 背景说明 2. 示例代码 buddySystem.h // 伙伴系统实现头文件#ifndef BUDDY_SYSTEM_H #define BUDDY_SYSTEM_H#include "errorRecord.h"#define POWER_TIME 10 // 可利用空间总容量的 2 的幂次,子表的个数为 POWER_TIME + 1 #define MAX_USED_BLOCK_NUM 100 //…

我的 Java 面试“打怪升级”之路01

前言 在当今的科技行业,Java 作为一门广泛应用的编程语言,其相关的岗位竞争可谓十分激烈。作为一名求职者,经历 Java 面试就如同一场充满挑战的“打怪升级”游戏。在这里,我想和大家分享一下我在 Java 面试中的一些经历和感悟。 …