案例系列:营销模型_客户细分_无监督聚类

案例系列:营销模型_客户细分_无监督聚类

import numpy as np # 线性代数库
import pandas as pd # 数据处理库,CSV文件的输入输出(例如pd.read_csv)
/kaggle/input/customer-personality-analysis/marketing_campaign.csv

在这个项目中,我将对来自一家杂货公司数据库的客户记录进行无监督聚类分析。客户细分是将客户分成反映每个群集中客户相似性的群组的实践。我将把客户分成不同的细分,以优化每个客户对业务的重要性。根据客户的不同需求和行为来调整产品。它还帮助企业满足不同类型客户的关注点。

# 目录
  • 1. 导入库

  • 2. 加载数据

  • 3. 数据清洗

  • 4. 数据预处理

  • 5. 降维

  • 6. 聚类

  • 7. 评估模型

  • 8. 个人资料

  • 9. 结论

  • 10. 结束

导入库

# 导入库
import numpy as np
import pandas as pd
import datetime
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import colors
import seaborn as sns
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from yellowbrick.cluster import KElbowVisualizer
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt, numpy as np
from mpl_toolkits.mplot3d import Axes3D
from sklearn.cluster import AgglomerativeClustering
from matplotlib.colors import ListedColormap
from sklearn import metrics
import warnings
import sys# 忽略警告
if not sys.warnoptions:warnings.simplefilter("ignore")# 设置随机种子
np.random.seed(42)

加载数据中

# 加载数据集
data = pd.read_csv("../input/customer-personality-analysis/marketing_campaign.csv", sep="\t")# 打印数据点的数量
print("Number of datapoints:", len(data))# 打印数据集的前几行数据
data.head()
Number of datapoints: 2240
IDYear_BirthEducationMarital_StatusIncomeKidhomeTeenhomeDt_CustomerRecencyMntWines...NumWebVisitsMonthAcceptedCmp3AcceptedCmp4AcceptedCmp5AcceptedCmp1AcceptedCmp2ComplainZ_CostContactZ_RevenueResponse
055241957GraduationSingle58138.00004-09-201258635...70000003111
121741954GraduationSingle46344.01108-03-20143811...50000003110
241411965GraduationTogether71613.00021-08-201326426...40000003110
361821984GraduationTogether26646.01010-02-20142611...60000003110
453241981PhDMarried58293.01019-01-201494173...50000003110

5 rows × 29 columns

数据情况

客户个性分析是对公司理想客户的详细分析。它帮助企业更好地了解其客户,并使其更容易根据不同类型客户的特定需求、行为和关注点来修改产品。

客户个性分析帮助企业根据不同类型客户群体中的目标客户来修改其产品。例如,公司可以分析哪个客户群体最有可能购买该产品,而不是花钱将新产品推销给公司数据库中的每个客户,然后只在该特定客户群体中推销该产品。

变量解释

人物

ID:客户的唯一标识符

Year_Birth:客户的出生年份

Education:客户的教育水平

Marital_Status:客户的婚姻状况

Income:客户的年收入

Kidhome:客户家庭中的儿童数量

Teenhome:客户家庭中的青少年数量

Dt_Customer:客户加入公司的日期

Recency:客户上次购买以来的天数

Complain:如果客户在过去2年中投诉,则为1,否则为0

产品

MntWines:过去2年中花费在葡萄酒上的金额

MntFruits:过去2年中花费在水果上的金额

MntMeatProducts:过去2年中花费在肉类上的金额

MntFishProducts:过去2年中花费在鱼类上的金额

MntSweetProducts:过去2年中花费在糖果上的金额

MntGoldProds:过去2年中花费在黄金上的金额

促销

NumDealsPurchases:使用折扣购买的次数

AcceptedCmp1:如果客户接受了第1次活动的优惠,则为1,否则为0

AcceptedCmp2:如果客户接受了第2次活动的优惠,则为1,否则为0

AcceptedCmp3:如果客户接受了第3次活动的优惠,则为1,否则为0

AcceptedCmp4:如果客户接受了第4次活动的优惠,则为1,否则为0

AcceptedCmp5:如果客户接受了第5次活动的优惠,则为1,否则为0

Response:如果客户接受了最后一次活动的优惠,则为1,否则为0

地点

NumWebPurchases:通过公司网站购买的次数

NumCatalogPurchases:使用目录购买的次数

NumStorePurchases:直接在商店购买的次数

NumWebVisitsMonth:上个月访问公司网站的次数属性

数据清洗

在本节中

  • 数据清洗
  • 特征工程

为了全面了解应该采取哪些步骤来清洗数据集。
让我们来看看数据中的信息。

# 打印数据集的信息
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2240 entries, 0 to 2239
Data columns (total 29 columns):#   Column               Non-Null Count  Dtype  
---  ------               --------------  -----  0   ID                   2240 non-null   int64  1   Year_Birth           2240 non-null   int64  2   Education            2240 non-null   object 3   Marital_Status       2240 non-null   object 4   Income               2216 non-null   float645   Kidhome              2240 non-null   int64  6   Teenhome             2240 non-null   int64  7   Dt_Customer          2240 non-null   object 8   Recency              2240 non-null   int64  9   MntWines             2240 non-null   int64  10  MntFruits            2240 non-null   int64  11  MntMeatProducts      2240 non-null   int64  12  MntFishProducts      2240 non-null   int64  13  MntSweetProducts     2240 non-null   int64  14  MntGoldProds         2240 non-null   int64  15  NumDealsPurchases    2240 non-null   int64  16  NumWebPurchases      2240 non-null   int64  17  NumCatalogPurchases  2240 non-null   int64  18  NumStorePurchases    2240 non-null   int64  19  NumWebVisitsMonth    2240 non-null   int64  20  AcceptedCmp3         2240 non-null   int64  21  AcceptedCmp4         2240 non-null   int64  22  AcceptedCmp5         2240 non-null   int64  23  AcceptedCmp1         2240 non-null   int64  24  AcceptedCmp2         2240 non-null   int64  25  Complain             2240 non-null   int64  26  Z_CostContact        2240 non-null   int64  27  Z_Revenue            2240 non-null   int64  28  Response             2240 non-null   int64  
dtypes: float64(1), int64(25), object(3)
memory usage: 507.6+ KB

从上面的输出中,我们可以得出以下结论和注意事项:

  • 收入中存在缺失值
  • Dt_Customer表示客户加入数据库的日期没有被解析为DateTime类型
  • 我们的数据框中有一些分类特征;因为有一些特征的数据类型是object类型。所以我们需要将它们转换为数值形式。

首先,对于缺失值,我打算简单地删除具有缺失收入值的行。

# 删除缺失值
data = data.dropna()
# 打印删除缺失值后的数据点总数
print("删除缺失值后的数据点总数为:", len(data))
The total number of data-points after removing the rows with missing values are: 2216

在下一步中,我将创建一个特征,即**“Dt_Customer”**,该特征表示客户在公司数据库中注册的天数。然而,为了简单起见,我将以相对于记录中最近的客户的值为基准。

因此,为了获得这些值,我必须检查最新和最旧的记录日期。

# 将"data"中的"Dt_Customer"列转换为日期格式
data["Dt_Customer"] = pd.to_datetime(data["Dt_Customer"])# 创建一个空列表"dates"用于存储日期
dates = []# 遍历"data"中的"Dt_Customer"列中的每个日期
for i in data["Dt_Customer"]:# 将日期转换为日期格式,只保留日期部分i = i.date()# 将日期添加到"dates"列表中dates.append(i)  # 打印最新和最旧记录的客户的日期
print("最新记录的客户的注册日期:", max(dates))
print("最旧记录的客户的注册日期:", min(dates))
The newest customer's enrolment date in therecords: 2014-12-06
The oldest customer's enrolment date in the records: 2012-01-08

创建一个特征**(“Customer_For”)**,表示顾客开始在商店购物的天数与最后记录日期相对应。

# 创建了一个名为"Customer_For"的特征days = []  # 创建一个空列表用于存储日期差值
d1 = max(dates)  # 将最大日期设为最新的客户日期# 遍历日期列表
for i in dates:delta = d1 - i  # 计算最新客户日期与当前日期的差值days.append(delta)  # 将差值添加到days列表中data["Customer_For"] = days  # 将days列表赋值给名为"Customer_For"的特征列data["Customer_For"] = pd.to_numeric(data["Customer_For"], errors="coerce")  # 将"Customer_For"特征列转换为数字类型,如果出现错误则设置为NaN

现在我们将探索分类特征中的唯一值,以便更清楚地了解数据。

# 打印出特征"Marital_Status"中的所有类别及其数量
print("特征Marital_Status中的所有类别及其数量:\n", data["Marital_Status"].value_counts(), "\n")# 打印出特征"Education"中的所有类别及其数量
print("特征Education中的所有类别及其数量:\n", data["Education"].value_counts())
Total categories in the feature Marital_Status:Married     857
Together    573
Single      471
Divorced    232
Widow        76
Alone         3
Absurd        2
YOLO          2
Name: Marital_Status, dtype: int64 Total categories in the feature Education:Graduation    1116
PhD            481
Master         365
2n Cycle       200
Basic           54
Name: Education, dtype: int64

在接下来的部分中,我将执行以下步骤来构建一些新的特征:

  • 通过**“Year_Birth"提取客户的"Age”**,表示相应人员的出生年份。
  • 创建另一个特征**“Spent”**,表示客户在两年内在各个类别上的总消费金额。
  • 从**“Marital_Status"中创建另一个特征"Living_With”**,以提取夫妻的居住情况。
  • 创建一个特征**“Children”**,表示一个家庭中的孩子和青少年的总数。
  • 为了更清楚地了解家庭情况,创建一个表示**“Family_Size”**的特征。
  • 创建一个特征**“Is_Parent”**,表示是否为父母。
  • 最后,我将通过简化其值计数来创建**“Education”**中的三个类别。
  • 删除一些冗余特征。
# 特征工程# 计算顾客的年龄
data["Age"] = 2021 - data["Year_Birth"]# 计算顾客在各种商品上的总消费金额
data["Spent"] = data["MntWines"] + data["MntFruits"] + data["MntMeatProducts"] + data["MntFishProducts"] + data["MntSweetProducts"] + data["MntGoldProds"]# 根据婚姻状况推断居住情况,将"Married"和"Together"替换为"Partner",将"Absurd"、"Widow"、"YOLO"、"Divorced"和"Single"替换为"Alone"
data["Living_With"] = data["Marital_Status"].replace({"Married": "Partner", "Together": "Partner", "Absurd": "Alone", "Widow": "Alone", "YOLO": "Alone", "Divorced": "Alone", "Single": "Alone"})# 计算家庭中的孩子数量
data["Children"] = data["Kidhome"] + data["Teenhome"]# 计算家庭成员总数
data["Family_Size"] = data["Living_With"].replace({"Alone": 1, "Partner": 2}) + data["Children"]# 根据是否有孩子来判断是否为父母
data["Is_Parent"] = np.where(data.Children > 0, 1, 0)# 将教育水平分为三个组别
data["Education"] = data["Education"].replace({"Basic": "Undergraduate", "2n Cycle": "Undergraduate", "Graduation": "Graduate", "Master": "Postgraduate", "PhD": "Postgraduate"})# 为了清晰起见,重命名一些特征列
data = data.rename(columns={"MntWines": "Wines", "MntFruits": "Fruits", "MntMeatProducts": "Meat", "MntFishProducts": "Fish", "MntSweetProducts": "Sweets", "MntGoldProds": "Gold"})# 删除一些冗余的特征列
to_drop = ["Marital_Status", "Dt_Customer", "Z_CostContact", "Z_Revenue", "Year_Birth", "ID"]
data = data.drop(to_drop, axis=1)

现在我们有了一些新功能,让我们来看一下数据的统计信息。

# 对数据进行描述性统计分析
data.describe()
IncomeKidhomeTeenhomeRecencyWinesFruitsMeatFishSweetsGold...AcceptedCmp1AcceptedCmp2ComplainResponseCustomer_ForAgeSpentChildrenFamily_SizeIs_Parent
count2216.0000002216.0000002216.0000002216.0000002216.0000002216.0000002216.0000002216.0000002216.0000002216.000000...2216.0000002216.0000002216.0000002216.0000002.216000e+032216.0000002216.0000002216.0000002216.0000002216.000000
mean52247.2513540.4417870.50541549.012635305.09160626.356047166.99593937.63763527.02888143.965253...0.0640790.0135380.0094770.1502714.423735e+1652.179603607.0753610.9472022.5925090.714350
std25173.0766610.5368960.54418128.948352337.32792039.793917224.28327354.75208241.07204651.815414...0.2449500.1155880.0969070.3574172.008532e+1611.985554602.9004760.7490620.9057220.451825
min1730.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0000000.000000...0.0000000.0000000.0000000.0000000.000000e+0025.0000005.0000000.0000001.0000000.000000
25%35303.0000000.0000000.00000024.00000024.0000002.00000016.0000003.0000001.0000009.000000...0.0000000.0000000.0000000.0000002.937600e+1644.00000069.0000000.0000002.0000000.000000
50%51381.5000000.0000000.00000049.000000174.5000008.00000068.00000012.0000008.00000024.500000...0.0000000.0000000.0000000.0000004.432320e+1651.000000396.5000001.0000003.0000001.000000
75%68522.0000001.0000001.00000074.000000505.00000033.000000232.25000050.00000033.00000056.000000...0.0000000.0000000.0000000.0000005.927040e+1662.0000001048.0000001.0000003.0000001.000000
max666666.0000002.0000002.00000099.0000001493.000000199.0000001725.000000259.000000262.000000321.000000...1.0000001.0000001.0000001.0000009.184320e+16128.0000002525.0000003.0000005.0000001.000000

8 rows × 28 columns

上述统计数据显示了平均收入和年龄以及最高收入和年龄之间存在一些差异。

请注意,最大年龄为128岁,因为我计算的年龄是今天(即2021年),而数据是旧的。

我必须从更广泛的数据视角来看待这些数据。
我将绘制一些选定的特征。


# 设置颜色偏好
sns.set(rc={"axes.facecolor":"#FFF9ED","figure.facecolor":"#FFF9ED"})
pallet = ["#682F2F", "#9E726F", "#D6B2B1", "#B9C0C9", "#9F8A78", "#F3AB60"]
cmap = colors.ListedColormap(["#682F2F", "#9E726F", "#D6B2B1", "#B9C0C9", "#9F8A78", "#F3AB60"])# 需要绘制的特征
To_Plot = [ "Income", "Recency", "Customer_For", "Age", "Spent", "Is_Parent"]# 输出提示信息
print("Reletive Plot Of Some Selected Features: A Data Subset")# 创建一个新的图形
plt.figure()# 绘制特征之间的关系图
sns.pairplot(data[To_Plot], hue= "Is_Parent", palette= (["#682F2F","#F3AB60"]))# 显示图形
plt.show()
Reletive Plot Of Some Selected Features: A Data Subset<Figure size 576x396 with 0 Axes>

在这里插入图片描述

显然,收入和年龄特征中存在一些异常值。
我将删除数据中的异常值。

# 删除异常值,通过设置年龄和收入的上限来进行筛选
data = data[(data["Age"]<90)]  # 筛选出年龄小于90的数据
data = data[(data["Income"]<600000)]  # 筛选出收入小于600000的数据
print("删除异常值后的数据点总数为:", len(data))  # 打印删除异常值后的数据点总数
The total number of data-points after removing the outliers are: 2212

下面,让我们来看一下特征之间的相关性。
(在这一点上,不包括分类属性)

# 计算相关系数矩阵
corrmat = data.corr()# 创建一个图像对象,设置图像大小为20x20
plt.figure(figsize=(20, 20))# 使用热力图可视化相关系数矩阵
# annot=True 表示在热力图上显示数值
# cmap=cmap 表示使用指定的颜色映射
# center=0 表示将颜色映射的中心值设置为0
sns.heatmap(corrmat, annot=True, cmap=cmap, center=0)
<AxesSubplot:>

在这里插入图片描述

数据非常干净,新特征已经包含在内。我将继续下一步,即对数据进行预处理。

数据预处理

在本节中,我将对数据进行预处理以进行聚类操作。

以下步骤用于预处理数据:

  • 对分类特征进行标签编码
  • 使用标准缩放器对特征进行缩放
  • 创建一个子数据框以进行降维处理
# 获取分类变量的列表
s = (data.dtypes == 'object')  # 将数据集中的数据类型为'object'的列标记为True,其他列标记为False
object_cols = list(s[s].index)  # 将标记为True的列的索引添加到object_cols列表中print("Categorical variables in the dataset:", object_cols)  # 打印数据集中的分类变量列表
Categorical variables in the dataset: ['Education', 'Living_With']
# 创建一个LabelEncoder对象
LE = LabelEncoder()# 对于每个object类型的列
for i in object_cols:# 使用LabelEncoder对象对该列进行编码,并将编码后的值赋给data[i]data[i] = data[[i]].apply(LE.fit_transform)# 打印输出提示信息,表示所有特征现在都是数值类型的
print("所有特征现在都是数值类型的")
All features are now numerical
# 创建数据的副本
ds = data.copy()# 创建一个数据子集,通过删除已接受的交易和促销特征
cols_del = ['AcceptedCmp3', 'AcceptedCmp4', 'AcceptedCmp5', 'AcceptedCmp1','AcceptedCmp2', 'Complain', 'Response']
ds = ds.drop(cols_del, axis=1)# 缩放数据
scaler = StandardScaler()
scaler.fit(ds)
scaled_ds = pd.DataFrame(scaler.transform(ds),columns= ds.columns )# 打印提示信息,表示所有特征已经被缩放
print("所有特征现在都已经被缩放")
All features are now scaled
# 打印提示信息,说明接下来要使用的是经过缩放的数据进行降维处理
print("用于进一步建模的数据框:")
# 打印经过缩放的数据的前几行,以便查看数据的结构和内容
scaled_ds.head()
Dataframe to be used for further modelling:
EducationIncomeKidhomeTeenhomeRecencyWinesFruitsMeatFishSweets...NumCatalogPurchasesNumStorePurchasesNumWebVisitsMonthCustomer_ForAgeSpentLiving_WithChildrenFamily_SizeIs_Parent
0-0.8935860.287105-0.822754-0.9296990.3103530.9776601.5520411.6902932.4534721.483713...2.503607-0.5558140.6921811.9735831.0183521.676245-1.349603-1.264598-1.758359-1.581139
1-0.893586-0.2608821.0400210.908097-0.380813-0.872618-0.637461-0.718230-0.651004-0.634019...-0.571340-1.171160-0.132545-1.6651441.274785-0.963297-1.3496031.4045720.4490700.632456
2-0.8935860.913196-0.822754-0.929699-0.7955140.3579350.570540-0.1785421.339513-0.147184...-0.2296791.290224-0.544908-0.1726640.3345300.2801100.740959-1.264598-0.654644-1.581139
3-0.893586-1.1761141.040021-0.929699-0.795514-0.872618-0.561961-0.655787-0.504911-0.585335...-0.913000-0.5558140.279818-1.923210-1.289547-0.9201350.7409590.0699870.4490700.632456
40.5716570.2943071.040021-0.9296991.554453-0.3922570.419540-0.2186840.152508-0.001133...0.1119820.059532-0.132545-0.822130-1.033114-0.3075620.7409590.0699870.4490700.632456

5 rows × 23 columns

降维

在这个问题中,有许多因素是基于这些因素进行最终分类的基础。这些因素基本上是属性或特征。特征的数量越多,处理起来就越困难。其中许多特征是相关的,因此是冗余的。这就是为什么在将它们输入分类器之前,我将对所选特征进行降维处理的原因。
降维是通过获取一组主要变量来减少考虑的随机变量的数量的过程。

**主成分分析(PCA)**是一种用于降低此类数据集维度的技术,增加可解释性,同时最小化信息损失。

本节的步骤:

  • 使用PCA进行降维
  • 绘制降维后的数据框

使用PCA进行降维

对于这个项目,我将把维度降低到3。

# 初始化PCA对象,将维度(特征)降低为3
pca = PCA(n_components=3)# 使用PCA拟合标准化后的数据集
pca.fit(scaled_ds)# 使用PCA将标准化后的数据集转换为降维后的数据集
PCA_ds = pd.DataFrame(pca.transform(scaled_ds), columns=(["col1","col2", "col3"]))# 对降维后的数据集进行描述性统计分析,并进行转置
PCA_ds.describe().T
countmeanstdmin25%50%75%max
col12212.0-1.116246e-162.878377-5.969394-2.538494-0.7804212.3832907.444305
col22212.01.105204e-161.706839-4.312196-1.328316-0.1581231.2422896.142721
col32212.03.049098e-171.221956-3.530416-0.829067-0.0226920.7998956.611222

# 获取数据
x = PCA_ds["col1"]
y = PCA_ds["col2"]
z = PCA_ds["col3"]# 创建一个图形对象
fig = plt.figure(figsize=(10,8))# 添加一个3D子图
ax = fig.add_subplot(111, projection="3d")# 绘制散点图
ax.scatter(x, y, z, c="maroon", marker="o")# 设置图标题
ax.set_title("A 3D Projection Of Data In The Reduced Dimension")# 显示图形
plt.show()

在这里插入图片描述

聚类

现在我已经将属性减少到三个维度,我将通过凝聚聚类来进行聚类。凝聚聚类是一种层次聚类方法。它涉及合并示例,直到达到所需的聚类数。

聚类中涉及的步骤

  • 肘部法确定要形成的聚类数
  • 通过凝聚聚类进行聚类
  • 通过散点图检查形成的聚类
# 快速检查肘部法则以确定要形成的聚类数量。
print('使用肘部法则确定要形成的聚类数量:')# 创建一个 KMeans 模型的肘部可视化器对象
Elbow_M = KElbowVisualizer(KMeans(), k=10)# 使用 PCA_ds 数据拟合肘部可视化器对象
Elbow_M.fit(PCA_ds)# 显示肘部可视化图
Elbow_M.show()
Elbow Method to determine the number of clusters to be formed:

在这里插入图片描述

<AxesSubplot:title={'center':'Distortion Score Elbow for KMeans Clustering'}, xlabel='k', ylabel='distortion score'>

上面的单元格表明对于这些数据来说,四个聚类是最优的。
接下来,我们将拟合凝聚聚类模型以获得最终的聚类。

# 导入AgglomerativeClustering模型
# 参数n_clusters=4表示将数据分为4个簇
AC = AgglomerativeClustering(n_clusters=4)# 使用数据PCA_ds训练模型并预测簇
yhat_AC = AC.fit_predict(PCA_ds)# 将预测的簇标签添加到PCA_ds数据集中的"Clusters"列
PCA_ds["Clusters"] = yhat_AC# 将预测的簇标签添加到原始数据集data中的"Clusters"列
data["Clusters"] = yhat_AC

为了检查形成的聚类,让我们来看一下聚类的三维分布。


# 创建一个图形对象
fig = plt.figure(figsize=(10,8))# 创建一个三维坐标轴对象
ax = plt.subplot(111, projection='3d', label="bla")# 绘制散点图
# x, y, z 分别为数据点的 x, y, z 坐标
# s 为散点的大小
# c 为散点的颜色,根据 PCA_ds 数据集中的 "Clusters" 列的值来确定颜色
# marker 为散点的形状
# cmap 为颜色映射
ax.scatter(x, y, z, s=40, c=PCA_ds["Clusters"], marker='o', cmap = cmap )# 设置图形标题
ax.set_title("The Plot Of The Clusters")# 显示图形
plt.show()

在这里插入图片描述

评估模型

由于这是一个无监督的聚类,我们没有一个标记的特征来评估或打分我们的模型。本节的目的是研究形成的聚类中的模式,并确定聚类模式的性质。

为此,我们将通过探索性数据分析和得出结论来查看聚类的数据。

首先,让我们看一下聚类的群组分布

# 定义颜色列表
pal = ["#682F2F","#B9C0C9", "#9F8A78","#F3AB60"]# 绘制计数图
pl = sns.countplot(x=data["Clusters"], palette= pal)# 设置图表标题
pl.set_title("Distribution Of The Clusters")# 显示图表
plt.show()

在这里插入图片描述

集群似乎分布相对均匀。


# 创建散点图
pl = sns.scatterplot(data=data, x=data["Spent"], y=data["Income"], hue=data["Clusters"], palette=pal)# 设置图表标题
pl.set_title("Cluster's Profile Based On Income And Spending")# 显示图例
plt.legend()# 显示图表
plt.show()

在这里插入图片描述

收入与支出图显示了集群模式

  • 第0组:高支出和平均收入
  • 第1组:高支出和高收入
  • 第2组:低支出和低收入
  • 第3组:高支出和低收入

接下来,我将根据数据中的各种产品来查看集群的详细分布。即:葡萄酒、水果、肉类、鱼类、糖果和黄金。

# 创建一个新的图形
plt.figure()# 使用swarmplot函数绘制散点图,x轴为数据中的"Clusters"列,y轴为数据中的"Spent"列
# 设置散点的颜色为"#CBEDDD",透明度为0.5
pl = sns.swarmplot(x=data["Clusters"], y=data["Spent"], color="#CBEDDD", alpha=0.5)# 使用boxenplot函数绘制箱线图,x轴为数据中的"Clusters"列,y轴为数据中的"Spent"列
# 设置调色板为pal
pl = sns.boxenplot(x=data["Clusters"], y=data["Spent"], palette=pal)# 显示图形
plt.show()

在这里插入图片描述

从上图可以清楚地看到,集群1是我们最大的一组客户,紧随其后的是集群0。
我们可以探索每个集群在目标营销策略上的消费情况。

让我们接下来探索一下我们过去的广告活动表现如何。

# 创建一个特征,用于计算接受的促销活动总数
data["Total_Promos"] = data["AcceptedCmp1"]+ data["AcceptedCmp2"]+ data["AcceptedCmp3"]+ data["AcceptedCmp4"]+ data["AcceptedCmp5"]# 绘制接受的总促销活动数量的计数图
plt.figure()
pl = sns.countplot(x=data["Total_Promos"],hue=data["Clusters"], palette= pal)
pl.set_title("Count Of Promotion Accepted")  # 设置图表标题
pl.set_xlabel("Number Of Total Accepted Promotions")  # 设置x轴标签
plt.show()  # 显示图表

在这里插入图片描述

概述

到目前为止,对于这些活动的反应并不强烈。总体参与者很少。此外,没有人参与了其中的全部5个活动。也许需要更有针对性和精心策划的活动来提升销售。


# 创建一个新的图形窗口
plt.figure()# 绘制盒图,y轴为"NumDealsPurchases"列的数据,x轴为"Clusters"列的数据
# 使用预定义的调色板"pal"来设置颜色
pl = sns.boxenplot(y=data["NumDealsPurchases"], x=data["Clusters"], palette=pal)# 设置图形标题为"Number of Deals Purchased"
pl.set_title("Number of Deals Purchased")# 显示图形
plt.show()

在这里插入图片描述

与营销活动不同,所提供的交易表现良好。它在群集0和群集3中有最佳结果。然而,我们的明星客户群集1对交易不太感兴趣。似乎没有什么能够极大地吸引群集2。

# 定义一个列表变量Places,包含了四个字符串元素,分别表示网购次数、目录购买次数、实体店购买次数和每月网站访问次数# 遍历Places列表中的每个元素
for i in Places:# 创建一个新的图形窗口plt.figure()# 绘制一个联合分布图,x轴为data[i],y轴为data["Spent"],颜色按照data["Clusters"]进行区分,颜色调色板为palsns.jointplot(x=data[i], y=data["Spent"], hue=data["Clusters"], palette=pal)# 显示图形plt.show()
<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

用户画像

现在我们已经形成了聚类并查看了他们的购买习惯。
让我们看看这些聚类中有谁。为此,我们将对形成的聚类进行画像,并得出结论,谁是我们的明星客户,谁需要零售店的营销团队更多的关注。

为了决定这一点,我将绘制一些指示客户个人特征的特征,以了解他们所在的聚类。根据结果,我将得出结论。


# 定义个人特征列表
Personal = ["Kidhome", "Teenhome", "Customer_For", "Age", "Children", "Family_Size", "Is_Parent", "Education", "Living_With"]# 遍历个人特征列表
for i in Personal:# 创建一个新的图形plt.figure()# 绘制联合分布图,x轴为数据中的个人特征i,y轴为数据中的"Spent"特征,根据"Clusters"特征进行着色,使用核密度估计图,颜色使用预定义的调色板palsns.jointplot(x=data[i], y=data["Spent"], hue=data["Clusters"], kind="kde", palette=pal)# 显示图形plt.show()
<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

<Figure size 576x396 with 0 Axes>

在这里插入图片描述

需要注意的要点:

可以从不同聚类中推断出以下关于客户的信息。

关于聚类编号:0

• 绝对是父母

• 家庭成员最多为4人,最少为2人

• 单亲家庭是这个群体的一个子集

• 大多数家庭有一个青少年

• 年龄相对较大

关于聚类编号:1

• 绝对不是父母

• 家庭成员最多只有2人

• 比例上,夫妻居多,单身人士次之

• 跨越各个年龄段

• 高收入群体

关于聚类编号:2

• 大多数人是父母

• 家庭成员最多为3人

• 他们主要只有一个孩子(通常不是青少年)

• 年龄相对较小

关于聚类编号:3

• 绝对是父母

• 家庭成员最多为5人,最少为2人

• 大多数家庭有一个青少年

• 年龄相对较大

• 低收入群体

结论

在这个项目中,我进行了无监督聚类。我使用了降维后的凝聚聚类。我得到了4个聚类,并根据他们的家庭结构和收入/支出对聚类中的客户进行了进一步的分析。这可以用于制定更好的营销策略。

代码链接

https://download.csdn.net/download/wjjc1017/88647434

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

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

相关文章

KoPA: Making Large Language Models Perform Better in Knowledge Graph Completion

本来这个论文用来组会讲的&#xff0c;但是冲突了&#xff0c;没怎么讲&#xff0c;记录一下供以后学习。 创新点 按照我的理解简单概述一下这篇论文的创新点 提出使用大模型补全知识图谱&#xff0c;并且融合知识图谱的结构信息提出一个新的模型KoPA模型&#xff0c;采用少…

JavaCV音视频开发宝典:UDP局域网组播推流,多播推流,局域网多网段推流,使用UDP方式推送TS组播流,实现UDP一对多组播

《JavaCV音视频开发宝典》专栏目录导航 《JavaCV音视频开发宝典》专栏介绍和目录 ​ 前言 在之前文章中我们已经实现rtp点到点传输JavaCV音视频开发宝典:rtp点到点音视频传输(一对一音视频直播)和rtp广播JavaCV音视频开发宝典:rtp广播方式发送TS流音视频传输(一对多音视…

Linux宝塔面板本地部署Discuz论坛发布到公网访问【无需公网IP】

文章目录 前言1.安装基础环境2.一键部署Discuz3.安装cpolar工具4.配置域名访问Discuz5.固定域名公网地址6.配置Discuz论坛 前言 Crossday Discuz! Board&#xff08;以下简称 Discuz!&#xff09;是一套通用的社区论坛软件系统&#xff0c;用户可以在不需要任何编程的基础上&a…

uni-app学习记录

uni-app官网学习记录 uni-app注意点记录 页面跳转注意事项 navigateTo, redirectTo 只能打开非 tabBar 页面。switchTab 只能打开 tabBar 页面。reLaunch 可以打开任意页面。不能在首页 onReady 之前进行页面跳转。 页面通讯 // 发起页面uni.$emit(update,{msg:页面更新})//…

软件设计模式:六大设计原则

文章目录 前言一、开闭原则二、里氏替换原则三、依赖倒转原则四、接口隔离五、迪米特法则六、合成复用原则总结 前言 在软件开发中&#xff0c;为了提高软件系统的可维护性和可复用性&#xff0c;增加软件的可扩展性和灵活性&#xff0c;程序员要尽量根据6条原则来开发程序&am…

Postman调用HTTPS需要配置

1、配置—Settings 2、General—SSL cert…&#xff1a;改成OFF 3、添加请求IP 欢迎大家阅读&#xff0c;本人见识有限&#xff0c;写的博客难免有错误或者疏忽的地方&#xff0c;还望各位大佬指点&#xff0c;在此表示感谢。觉得本文章有帮助到的&#xff0c;点个赞呗

项目进度管理:掌握进度管理技巧,保障项目不延期

项目进度问题通常在小型团队中并不显著&#xff0c;因为这类团队通常人数较少&#xff0c;成员间的沟通成本相对较低。这使得他们在执行项目时更加团结和协作。 然而&#xff0c;当团队规模扩大到上百人时&#xff0c;这使得沟通变得更为复杂&#xff0c;在这个庞大的团队中&…

JAVA线上事故:递归导致的OOM

最近因为人员离职&#xff0c;接手一个项目&#xff0c;是xxljob的客户端&#xff0c;部署在k8s上&#xff0c;在排查线上工单时&#xff0c;发现了一个问题&#xff1a; 在管理界面上&#xff0c;我惊讶的发现&#xff0c;三个月的时间&#xff0c;2个Pod&#xff0c;每个都重…

debian10安装配置vim+gtags

sudo apt install global gtags --version gtags //生成gtag gtags-cscope //查看gtags gtags与leaderf配合使用 参考: 【VIM】【LeaderF】【Gtags】打造全定制化的IDE开发环境&#xff01; - 知乎

以ACM32F403为主控的车载电动尾门案例分析

方案概述 随着汽车行业智能化、电气化、网联化大潮的发展&#xff0c;电动后尾门逐渐普及化。此方案兼容多种人机交互接口&#xff0c;包括传统的按键开关&#xff0c;也包括智能脚踢传感器&#xff0c;远程手机控制等智能控制技术&#xff0c;支持防夹算法&#xff0c;支持全锁…

Apache+PHP环境配置 手动配置

准备工作&#xff0c;在G盘新建一个WAMP目录 1.获取Apache 打开下载地址Apache VS17 binaries and modules download&#xff0c;下载 httpd-2.4.58-win64-VS17.zip 将下载好的httpd-2.4.58-win64-VS17.zip拷贝到G:\WAMP目录下并解压到当前目录&#xff0c;得到Apache24目录 …

u盘加密软件合辑丨u盘怎么上锁某个文件夹

毫无疑问&#xff0c;U盘是我们生活中最常使用的移动储存设备&#xff0c;常见的U盘普遍没有使用限制&#xff0c;任何人都可以浏览其中的数据&#xff0c;这就可能导致数据泄密和隐私泄露&#xff0c;那么普通U盘怎么变成加密U盘呢&#xff1f; 一、上锁某个U盘文件夹 可以将…

Vue3+Echarts:堆积柱状图的绘制

一、需求 在Vue3项目中&#xff0c;想用Echarts来绘制堆积柱状图&#xff0c;去展示最近一周APP在不同渠道的登录人数效果如下&#xff1a; 二、实现 (关于Echarts的下载安装以及图表的样式设计&#xff0c;此处不展开&#xff01;) 1、Templates部分 <template>&l…

向本地maven中加载依赖

1、现在maven官网仓库找到相应依赖 Maven Repository: Search/Browse/Explore (mvnrepository.com) 2、下载相应jar包 3、使用maven命令在jar所在文件加内cmd运行 注意修改参数 -DgroupId&#xff1a;表示jar对应的groupId <groupId>io.confluent</groupId>…

菜鸟进阶数据大牛:如何系统学习BI商业智能

在这个信息爆炸式增长的时代&#xff0c;挖掘数据的潜在价值尤为重要&#xff0c;越来越多的人将目光聚集于商务智能BI领域。通过数据分析软件对来自不同的数据源进行统一的处理和管理&#xff0c;并以灵活的方式展示数据之间的联系&#xff0c;辅助企业进行决策。 在BI越发重…

MATLAB - 最优控制(Optimal Control)

系列文章目录 前言 - 什么是最优控制&#xff1f; 最优控制是动态系统满足设计目标的条件。最优控制是通过执行以下定义的最优性标准的控制律来实现的。一些广泛使用的最优控制方法有&#xff1a; 线性二次调节器 (LQR)/线性二次高斯 (LQG) 控制 模型预测控制 强化学习 极值…

HBase基础知识(一):HBase简介、HBase数据模型与基本架构

第1章HBase简介 1.1HBase定义 HBase是一种分布式、可扩展、支持海量数据存储的NoSQL数据库。 1.2HBase数据模型 逻辑上&#xff0c;HBase的数据模型同关系型数据库很类似&#xff0c;数据存储在一张表中&#xff0c;有行有列。但从HBase的底层物理存储结构&#xff08;K-V&a…

【Spring教程31】SSM框架整合实战:从零开始学习SSM整合配置,如何编写Mybatis SpringMVC JDBC Spring配置类

目录 1 流程分析2 整合配置2.1 步骤1&#xff1a;创建Maven的web项目2.2 步骤2:添加依赖2.3 步骤3:创建项目包结构2.4 步骤4:创建SpringConfig配置类2.5 步骤5:创建JdbcConfig配置类2.6 步骤6:创建MybatisConfig配置类2.7 步骤7:创建jdbc.properties2.8 步骤8:创建SpringMVC配置…

【MyBatis Plus】Service Mapper内置接口讲解

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《MyBatis-Plus》。&#x1f3af;&#x1f3af; &am…

java借助代理ip,解决访问api频繁导致ip被禁的问题

前言 Java是一种非常流行的编程语言&#xff0c;许多开发者经常使用Java来开发各种类型的应用程序&#xff0c;包括访问API。然而&#xff0c;由于频繁访问API可能导致IP被禁的问题&#xff0c;我们需要借助代理IP来解决这个问题。 本文将为您展示如何使用Java借助代理IP来解…