vlambda博客
学习文章列表

基于聚类算法(Kmeans)对电商用户做分群处理

在做该项目前,我先简单介绍Kmeans算法:

from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs

# n_samples 样本的个数:一行就是一个样本,整个样本的集合称之为样本集
# n_features 特征的个数:字段的个数
# centers 中心的个数
# cluster_std 聚类的标准方差:可以分别设置每一组数据的离散程度
# shuffle 随机,默认为True
X, y = make_blobs(n_samples=100, n_features=2, centers=2)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

# 其中参数x, y, c指颜色,按y进行分色, cmap指样式
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Accent)

我们在做聚类之前,只有一个样本集X,并不知道哪些可以分为一类,即并没有y值的存在,需要使用聚类算法得到这个y值,所以我们要用聚类算法得到y值与真实的y值进行比较,这样我们就可以知道聚类的好坏。聚类之前通常是要先知道我们要聚类的个数(由业务需求而定)。

# 假设现在需要对数据聚类为2类
kmeans = KMeans(n_clusters=2)

# 喂数据 fit 被动学习(人为进行喂数据的过程)
# X就是要聚类的样本数据,统计数据样本点在空间的位置
kmeans.fit(X)

# 预测数据 predict  必须先要fit才能predict
y_ = kmeans.predict(X)

plt.figure(figsize=(12, 5))  # 构建一个画板

ax1 = plt.subplot(1, 2, 1)
ax2 = plt.subplot(1, 2, 2)
ax1.set_title('True')
ax2.set_title('Predict')

ax1.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Accent)
ax2.scatter(X[:, 0], X[:, 1], c=y_, cmap=plt.cm.Accent)

# 绘制聚类中心scatter
centers = kmeans.cluster_centers_
ax2.scatter(centers[:, 0], centers[:, 1], c='red')
# 这个聚类中心代表着这一类群体代表的特征,不光光指的是一个点

基于聚类算法(Kmeans)对电商用户做分群处理

# 样本集 X
# 样本标签 y

# 聚类
# 1.确定聚类的个数(业务目标)
# 2.构造聚类算法对象KMeans(n_cluster=k)
# 3.fit数据  kmeans.fit(X)
# 4.predict数据,得到一个预测结果的y_=kmeans.predict(X)

# KMeans算法的一些常用属性

# 聚类中心
kmeans.cluster_centers_

kmeans.predict(X)

基于聚类算法(Kmeans)对电商用户做分群处理

# kmeans fit之后,就已经知道了对于训练的样本集聚类的结果
# 本质就是predict(x)的结果
kmeans.labels_

基于聚类算法(Kmeans)对电商用户做分群处理

中国足球水平分析

zoo = pd.read_table('AsiaZoo.txt', header=None, sep=',')
zoo.columns = ['国家''2006世界杯''2010世界杯''2007世界杯']
zoo

基于聚类算法(Kmeans)对电商用户做分群处理

我们对于特征的选取,需要根据业务目标,选择有效字段,在这里我们是研究球队的水平,所以特征应该去除那些对水平有影响的字段,所以我们这里只选择三次比赛的成绩排名。

注:建模是为了解决业务逻辑上的问题,当我们对某些指标取不到量化的字段的时候,我们就需要埋点操作了,并且我们埋点的逻辑也应该正确,获取用户的信息不能有偏差。

X = zoo[['2006世界杯''2010世界杯''2007世界杯']]
# 把球队划分为3个不同的水平
kmeans = KMeans(n_clusters=3)

# 训练模型
kmeans.fit(X)

基于聚类算法(Kmeans)对电商用户做分群处理

kmeans.predict(X)

基于聚类算法(Kmeans)对电商用户做分群处理

kmeans.labels_

基于聚类算法(Kmeans)对电商用户做分群处理

# 两步变为一步
y_ = kmeans.fit_predict(X)
# 虽然标签变了,但是本质时一样的,还是归类为一类
y_

基于聚类算法(Kmeans)对电商用户做分群处理

# 保存结果
zoo['y'] = y_
for k, v in zoo.groupby('y').groups.items():
    print(zoo.loc[v, '国家'])

# 聚类中心可以描述每一组数据的平均水平
# 经常也会使用聚类中心做一些可视化的说明
kmeans.cluster_centers_

基于聚类算法(Kmeans)对电商用户做分群处理

centers = pd.DataFrame(data=kmeans.cluster_centers_, columns=X.columns)
map_dict = {
    0'中',
    1'差',
    2'强'
}
zoo['水平'] = zoo.y.map(map_dict)

zoo

基于聚类算法(Kmeans)对电商用户做分群处理


聚类算法使用过程当中常见的问题

from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

# 1.K值不合理:不同的K值得到的结果是不一样的

X, y = make_blobs(n_samples=150, n_features=2, centers=3, random_state=4)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Accent)
# 添加一个随机种子random_state = 4, 作用是随机后的结果永远保持一样的

基于聚类算法(Kmeans)对电商用户做分群处理

# 解释随机种子的作用,种子可以限定随机的策略,不同的种子得到的随机结果不同,相同的种子得到的结果相同
np.random.seed(3)
np.random.randint(0, 100) = 24
# 2.数据偏差
trans = np.array([[0.6, -0.6], [-0.4, 0.8]])
# 点乘之后会形成数据的偏差
X2 = np.dot(X, trans)
X2.shape
(150, 2)
# 查看引入数据偏差之后的数据分布
plt.scatter(X2[:, 0], X2[:, 1], c=y, cmap=plt.cm.Accent)

基于聚类算法(Kmeans)对电商用户做分群处理

# 对比引入偏差后数据的分布
plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Accent)
plt.title('True')

plt.subplot(1, 2, 2)
plt.scatter(X2[:, 0], X2[:, 1], c=y, cmap=plt.cm.Accent)
plt.title('Trans')

基于聚类算法(Kmeans)对电商用户做分群处理

kmeans = KMeans(n_clusters=3)

# 我们统计的数据是有偏差的X2,所以对这个数据进行聚类,
# 查看结果在原始数据上的结果,和原始数据上的真是情况作对比
y_ = kmeans.fit_predict(X2)

plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Accent)
plt.title('True')

plt.subplot(1, 2, 2)
plt.scatter(X2[:, 0], X2[:, 1], c=y_, cmap=plt.cm.Accent)
plt.title('Predict')

基于聚类算法(Kmeans)对电商用户做分群处理

# 结论:数据偏差对我们建模的影响是巨大的
# 原则上,我们建模就是想进各种办法尽可能缩小数据噪声对模型的影响
# 如果数据质量较好的情况下,模型都很好,但是实际情况下不是这样的,而且模型准确度的波动也是非常大的

# 3.标准差不同  簇
# 聚类和分类是两个不同的概念
X, y = make_blobs(n_samples=150, n_features=2, centers=3,
                  cluster_std=[0.8, 1.3, 3], random_state=6)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Accent)

# cluster_std = 1.0默认情况下,每一簇数据之间的标准方差都是1

基于聚类算法(Kmeans)对电商用户做分群处理


kmeans = KMeans(n_clusters=3)

y_ = kmeans.fit_predict(X)

plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Accent)
plt.title('True')

plt.subplot(1, 2, 2)
plt.scatter(X2[:, 0], X2[:, 1], c=y_, cmap=plt.cm.Accent)
plt.title('Predict')

基于聚类算法(Kmeans)对电商用户做分群处理

# 标准差不同,也会影响预测的结果

# 4. 样本不均衡

X, y = make_blobs(n_samples=1500, n_features=2, centers=3)

pd.Series(y).value_counts()

基于聚类算法(Kmeans)对电商用户做分群处理

X1 = X[y == 0][:100]
X2 = X[y == 1][:40]
X3 = X[y == 2][:10]

X_N = np.concatenate((X1, X2, X3))
y_N = [0]*100 + [1]*40 + [2]*10

plt.scatter(X_N[:, 0], X_N[:, 1], c=y_, cmap=plt.cm.Accent)

基于聚类算法(Kmeans)对电商用户做分群处理


kmeans = KMeans(n_clusters=3)

y_ = kmeans.fit_predict(X_N)

plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.scatter(X_N[:, 0], X_N[:, 1], c=y_N, cmap=plt.cm.Accent)
plt.title('True')

plt.subplot(1, 2, 2)
plt.scatter(X_N[:, 0], X_N[:, 1], c=y_, cmap=plt.cm.Accent)
plt.title('Predict')

基于聚类算法(Kmeans)对电商用户做分群处理

# 所有的建模过程中,此类问题都有影响(普遍性问题)
# 总结:
# 1.k值不合理
# 2.数据偏差
# 3.数据标准方差不同
# 4.样本不均衡

# 聚类的评价策略:轮廓系数s  越接近1则说明分类越优秀

# 最好的聚类结果:簇内最紧凑,簇外距离越大越好,但是要根据业务目标为需求

# dis mean in:该点与本类点其他点的平均距离
# dismeanout:该点与非本类点其他点的平均距离

# 所有点的轮廓系数都要算出来,然后我们选择一个综合性指标来衡量好坏

# 使用轮廓系数,比较不同的kmeans聚类策略的优劣

X, y = make_blobs(n_samples=150, n_features=4, centers=3, random_state=4)

# metrics 所有机器学习算法的评价指标都在这个包中
from sklearn.metrics import silhouette_samples, silhouette_score

for k in range(2, 5):
    kmeans = KMeans(n_clusters=k)
    kmeans.fit(X)

    score = silhouette_score(X, kmeans.labels_)
    print(f'聚类个数{k},平均轮廓系数为{score}')

基于聚类算法(Kmeans)对电商用户做分群处理

kmeans = KMeans(n_clusters=3)
y_ = kmeans.fit_predict(X)

# 计算每一个样本点的轮廓系数:我这只显示前五行
silhouette_samples(X, y)

基于聚类算法(Kmeans)对电商用户做分群处理

# 1.没有特定的聚类个数的需求,以轮廓系数最高为准
# 2.如果有特定的聚类个数的需求,优化数据质量(特征提取,特征预处理,特征转换,降噪),尽可能的提升轮廓系数的值


Kmeans图像压缩

 # 稀疏矩阵:0值较多的矩阵,有效数字较少,节省内存的开销
# 每一个颜色所对应的就是一个三元组(0.2,0.3,0.4)
# 每一个图片就是RGB元组的集合,且是一个二维表格,再对所有颜色做一个聚类
# 新的图像只有聚类中心的颜色表示的元组,所以达成了图像压缩的目的

# kmeans图像压缩

# png : 0-1 float32类型 
# jpg : 0-255  uint8格式(unsigned无符号,意味着之只能存放正数)

# Byte:是计算机处理数据最基本的单元  1字节  2^8  0-256  (-127,128)
# bit:是计算机存储数据最基本的单元  2
# 8bit = 1Byte

import matplotlib.pyplot as plt
import seaborn as sns

img = plt.imread('lss.jpg')

img.shape
(1050, 1680, 3)
img.dtype
dtype('uint8')
# 逻辑:把一张彩色图像看成是一个RGB元组的集合,所以可以把每一个RGB元组看成是一个样本

# 机器学习,对data有一个形式上的要求
# VSM结构  vector space model == 二维数据表格,因为以为的数据机器学习处理不了

# 二维表格的特点:一行数据表示的一个样本,一列数据表示的是样本的一个特征

img.reshape(-1,3)
array([[48, 50, 39],
[48, 50, 39],
[49, 51, 40],
...,
[69, 58, 38],
[70, 59, 39],
[69, 61, 40]], dtype=uint8)
X = img.reshape(-1,3)

# 聚类的目的,就是对图像转换得到的X数据进行聚类,对颜色聚类,所以聚类中心也是一个颜色
from sklearn.cluster import KMeans

# 5个颜色表现图像
kmeans = KMeans(n_clusters=5)
kmeans.fit(X)
KMeans(n_clusters=5)
# 获取聚类中心
centers = kmeans.cluster_centers_
centers = centers/255
centers[kmeans.labels_].shape
new_img =centers[kmeans.labels_].reshape(img.shape)
new_img
array([[[0.25201295, 0.22271589, 0.17363865],
[0.25201295, 0.22271589, 0.17363865],
[0.25201295, 0.22271589, 0.17363865],
...,
        [0.25201295, 0.22271589, 0.17363865],
[0.25201295, 0.22271589, 0.17363865],
[0.25201295, 0.22271589, 0.17363865]]])
plt.figure(figsize=(12, 5))

plt.subplot(1,2,1)
plt.imshow(new_img)

plt.subplot(1,2,2)
plt.imshow(img)

基于聚类算法(Kmeans)对电商用户做分群处理

a = kmeans.cluster_centers_/255
sns.palplot(a)

基于聚类算法(Kmeans)对电商用户做分群处理

kmeans.labels_
array([0, 0, 0, ..., 0, 0, 0])


用户价值分群

准确的客户分类的结果是企业优化营销资源的重要依据,基于某电商公司的部分数据,采用Kmeans聚类方法,对某公司的客户进行聚类分析,识别出不同的客户群体特征,从而发现有用的客户。


我们使用的聚类算法:无监督学习,KMeans算法


对用户进行一个价值分层,有一个重要的模型RFM

RMF(描述电商用户的价值的核心三大指标)

R:最近的消费时常,可以用来评价用户对我们店铺的熟悉度

F:统计周期内的付费频率,可以用来说明用户对我们店铺的认可度较高

M:统计周期内的付费总额, 可以用来衡量用户的购买力


需求:我要对电商用户做一个价值分群

目的:对客户进行精准营销


价值分群(标签化)8个维度


精准营销

1.营销的用户群是固定的,比如公司只做3中活动策划,要覆盖掉公司所有用户

2.不同用户群体特征抽象,用户特征的维度很高

数据分析:把数字呈现出来,将上面的RMF标签化


运营:按照划分的情况,来做运营

数据分析:复盘,我们的划分策略,是否是正向的作用(销量是否哦提升了,新增用户是否提升了

GMV是否提高了,不同价值的用户比例是否发生了变化)

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
% matplotlib
inline
import warnings
warnings.filterwarnings('ignore')

order = pd.read_excel('./电商用户价值挖掘.xlsx', engine='openpyxl')
order.head(2)

基于聚类算法(Kmeans)对电商用户做分群处理

order.drop(labels=['品牌名称'], axis=1, inplace=True)
order.head()

基于聚类算法(Kmeans)对电商用户做分群处理

# RFM模型
order.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 28833 entries, 0 to 28832
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 品牌名称 28833 non-null object
1 买家昵称 28833 non-null object
2 付款日期 28833 non-null datetime64[ns]
3 订单状态 28833 non-null object
4 实付金额 28833 non-null int64
5 邮费 28833 non-null int64
6 省份 28833 non-null object
7 城市 28832 non-null object
8 购买数量 28833 non-null int64
dtypes: datetime64[ns](1), int64(3), object(5)
memory usage: 2.0+ MB
# 半年内的交易数据
order['付款日期'].min(), order['付款日期'].max()
(Timestamp('2019-01-01 00:17:59'), Timestamp('2019-06-30 22:46:22.511000'))
# 计算R值(天)

end_time = order['付款日期'].max()
end_time
Timestamp('2019-06-30 22:46:22.511000')
(order['付款日期'].max() - order['付款日期'].min())
Timedelta('180 days 22:28:23.511000')
R = end_time - order['付款日期']
R
0       180 days 22:28:23.511000
1 180 days 21:46:28.511000
2 180 days 14:57:34.511000
3 180 days 13:30:33.511000
4 180 days 12:46:49.511000
...
28828 0 days 00:24:13.511000
28829 0 days 00:12:39.738000
28830 0 days 00:09:29.621000
28831 0 days 00:01:44.119000
28832 0 days 00:00:00
Name: 付款日期, Length: 28833, dtype: timedelta64[ns]
order.head(1)

基于聚类算法(Kmeans)对电商用户做分群处理

order['买家昵称'].value_counts()
小kk铺              16
凯d歌 7
9engineleun1 7
1简单_4 5
2tb291666 5
..
8wanglin073 1
女拿相机生 1
1tb1117391_22 1
2郭小猫11 1
2yangcheng9015 1
Name: 买家昵称, Length: 25949, dtype: int64
# 每一个用户应该使用他最近一次付款时间来计算R值
# 根据用户分组,获取付款时间的最大值,这个值就是想要的
order.groupby('买家昵称')['付款日期'].max()
买家昵称
.blue_ram 2019-02-04 17:49:34.000
.christiny 2019-01-29 14:17:15.000
.willn1 2019-01-11 03:46:18.000
.托托m 2019-01-11 02:26:33.000
0000妮 2019-06-28 16:53:26.458
...
龙火师 2019-04-07 08:43:00.000
龙魔鬼女 2019-04-19 22:14:24.000
龟mil宝 2019-06-19 04:26:30.589
!谢鹏逗逼?2019-06-06 11:14:52.000
~小邱~ 2019-01-23 23:51:51.457
Name: 付款日期, Length: 25949, dtype: datetime64[ns]
# GMV  交易总额(包含退费的)
# 我们把付款失败的数据作为异常数据过滤掉

order['订单状态'].value_counts()
交易成功                 27793
付款以后用户退款成功,交易自动关闭 1040
Name: 订单状态, dtype: int64
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.sans-serif'] = 'SimHei'

plt.figure(figsize=(55))
order['订单状态'].value_counts().plot(kind='pie', autopct='%.2f%%')

基于聚类算法(Kmeans)对电商用户做分群处理

condition = order['订单状态'] == '交易成功'
order = order.loc[condition]
order['订单状态'].value_counts()
交易成功    27793
Name: 订单状态, dtype: int64
# 重新计算R值
r_value = (end_time - order.groupby('买家昵称')['付款日期'].max()).dt.days

r_value
买家昵称
.blue_ram 146
.christiny 152
.willn1 170
.托托m 170
0000妮 2
...
龙火师 84
龙魔鬼女 72
龟mil宝 11
!谢鹏逗逼?24
~小邱~ 157
Name: 付款日期, Length: 25420, dtype: int64
# 转换成一个标准的DataFrame格式,方便后续做数据汇总的操作
r_value.name = 'R'
R = pd.DataFrame(r_value)

# 计算F值
# 只需要对用户名称进行次数统计就可以得到用户的付款次数
f_value = order['买家昵称'].value_counts()
f_value.name = 'F'
F = pd.DataFrame(f_value)
F

基于聚类算法(Kmeans)对电商用户做分群处理

# 计算M值
# 每一个用户的付款总额
order.head()

基于聚类算法(Kmeans)对电商用户做分群处理

m_value = order.groupby('买家昵称')['实付金额'].sum()
m_value.name = 'M'
M = pd.DataFrame(data=m_value)

M

基于聚类算法(Kmeans)对电商用户做分群处理

# 汇总RMF三个值
temp = pd.merge(left=R, right=F, left_index=True, right_index=True)
temp

基于聚类算法(Kmeans)对电商用户做分群处理

total = pd.merge(left=temp, right=M, left_index=True, right_index=True)
total

基于聚类算法(Kmeans)对电商用户做分群处理

# 基于这三个维度,将每个维度分为高低两种情况,我们构建了一个三维的坐标系

# 确定阈值,一定要观察数据本身的分布情况
# (直方图) kde
# 平均值 或 中位数(如果数据有异常时,经常会使用,否则使用平均值)
sns.histplot(data=total, x='R')

基于聚类算法(Kmeans)对电商用户做分群处理

sns.histplot(data=total, x='F')
# 说明右侧是有异常数据的,某些用户的消费次数比较多

基于聚类算法(Kmeans)对电商用户做分群处理

total.F.value_counts()
# 几乎可以确认只要有复购行为的用户都属于高价值用户
1     23367
2 1795
3 217
4 33
5 5
15 1
7 1
6 1
Name: F, dtype: int64
sns.histplot(data=total, x='M')

基于聚类算法(Kmeans)对电商用户做分群处理

# 我们先之观察1000以内的
temp = total.loc[total.M < 1000]
sns.histplot(data=temp, x='M')

基于聚类算法(Kmeans)对电商用户做分群处理

# 说明从300以外的用户都是比较大的群体

# R值: 中位数
# F:1
# M: 中位数
# 根据这八个值,对象限进行划分

total['R_V'] = total.R.map(lambda x: (x < total.R.median()) * 1)
# bool值变成整数
total['F_V'] = total.F.map(lambda x: (x > 1) * 1)
total['M_V'] = total.R.map(lambda x: (x < total.M.median()) * 1)
total

基于聚类算法(Kmeans)对电商用户做分群处理

# 重要发展客户(1 0 1)
# 重要价值客户(1 1 1)
# 一般发展客户(1 0 0)
# 一般价值客户(1 1 0)
# 一般保持客户(0 1 0)
# 一般挽留客户(0 0 0)
# 重要保持客户(0 1 1)
# 重要挽留客户(0 0 1)
total.head()

基于聚类算法(Kmeans)对电商用户做分群处理

total['VALUE'] = total.R_V * 100 + total.F_V * 10 + total.M_V * 1
total

基于聚类算法(Kmeans)对电商用户做分群处理

# 处理映射关系
map_dict = {
    101'重要发展客户',
    111'重要价值客户',
    100'一般发展客户',
    110'一般价值客户',
    10'一般保持客户',
    0'一般挽留客户',
    11'重要保持客户',
    1'重要挽留客户'
}
total['VALUE'] = total['VALUE'].map(map_dict)
total['VALUE']
.blue_ram     NaN
.christiny NaN
.willn1 NaN
.托托m NaN
0000妮 NaN
...
龙火师 NaN
龙魔鬼女 NaN
龟mil宝 NaN
!谢鹏逗逼?NaN
~小邱~ NaN
Name: VALUE, Length: 25420, dtype: object
# 只能看到用户价值的比例
# 二八原则

# 聚类算法去解决更复杂的业务问题
# 但是并不是说机器学习算法比统计学的方法更好
# 方法只是说适不适合,从很多维度去考量的因素,比如技术团队的能力,资金的成本
# 聚类只是一种新的解决的思路

# 衡量两组数据是否相似:
# 1.采集的字段是否合理
# 2.数据需要量化,只有量化计算机才可以进行运算,否则没有评比的意义(如何量化的问题)

# 向量\矢量: 有大小和有方向的量,通常时用元组或者列表来表示
# 夹角代表向量的方向,长度代表向量的大小
# 欧氏距离(两个向量的距离,就是两组数据的相似性评估的方式)

# 聚类分析
# 找到更相似的群体
# 思路是什么?

from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

# 读取用户价值表
user_value = pd.read_excel('user_value.xlsx', engine='openpyxl')
user_value.head()

基于聚类算法(Kmeans)对电商用户做分群处理

# 后面的丢失了精度,所以我们应该从原始字段开始做分析
X = user_value[['R''F''M']].copy()

kmeans = KMeans(n_clusters=3)
kmeans.fit(X)
KMeans(n_clusters=3)
kmeans.labels_
array([1, 0, 1, ..., 0, 1, 0])
RFM_VALUE = pd.DataFrame(data=kmeans.cluster_centers_, columns=['R''F''M'])
# 聚类中心:代表每一簇数据代表性的价值
RFM_VALUE

基于聚类算法(Kmeans)对电商用户做分群处理

# 我们将我们的客户分为几个有特点的群体

# 一般需要考虑三个结果:
# 现在的聚类中心能描述用户特征吗?能不能有可视化的方案?能推行下去吗,符合业务的需求吗?

# 现在的结果有很多问题

# 聚类数据中有异常没有处理
# 聚类结果,辨识度并不高,可视化方案

centers = kmeans.cluster_centers_
centers
array([[9.05621057e+01, 1.21550637e+00, 2.31400505e+02],
[1.00431942e+02, 1.02868435e+00, 8.88068747e+01],
[5.80000000e+01, 8.50000000e+00, 5.36900000e+03]])
# 实现聚类结果的可视化函数:绘制雷达图(线型图,结合极坐标系)
def show_features(centers):
    plt.axes(polar=True)
    for row in range(centers.shape[0]):
        # row_data就是一类用户的特征描述,里面有RMF三个字段
        data = centers[row]
        x = np.linspace(02 * np.pi, 3, endpoint=False)
        x = np.concatenate((x, [x[0]]))
        data = np.concatenate((data, [data[0]]))

        plt.plot(x, data, label=str(row))
    plt.xticks(np.linspace(02 * np.pi, 3, endpoint=False), ['R''F''M'])
    plt.legend()

show_features(centers)

基于聚类算法(Kmeans)对电商用户做分群处理

# 观察聚类结果发现:
# 1.数据簇之间没有辨识度可言
# 2.异常值明显
X

基于聚类算法(Kmeans)对电商用户做分群处理

# 根据数据分布,M值的主要消费区间在0-300之间,所以如果高于这个区间的用户,我们可以使用统一的300填充
# 因为我们的目标就是区分他是高价值还是低价值
sns.displot(X.loc[X.M < 400])

基于聚类算法(Kmeans)对电商用户做分群处理

X.loc[X.M >= 300'M'] = 300

# 异常值有几种处理方式(过滤,填充)
# 1.99分位数过滤
# 2.3std过滤
# 3.离群点检测

sns.displot(X.loc[X.M])

基于聚类算法(Kmeans)对电商用户做分群处理

# 关于F字段用户的异常值的处理,使用4来填充所有高于4次的购买次数
sns.distplot(X.F)

基于聚类算法(Kmeans)对电商用户做分群处理

X.loc[X.F >= 3'F'] = 3
sns.distplot(X.F)

基于聚类算法(Kmeans)对电商用户做分群处理

# 为什么处理异常?

# 建模类的需求:异常数据必须解决(往往找的是公共性的特点)
# 统计类需求:异常数据可以不解决

# cluster_centers_这个数据就是由平均值得来的,所以聚类分析,必须要做异常数据的过滤
# 平均值会受到异常值的影响,所以异常值必须处理

# 异常处理之后,再聚类分析
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)
KMeans(n_clusters=3)
centers = kmeans.cluster_centers_
centers
array([[ 94.40514632,   1.22023209, 227.72174571],
[ 35.48436044, 1.04991348, 96.45268202],
[145.48572001, 1.01903998, 89.5019541 ]])
# 0  重要发展用户 (R值比较小,对店铺的印象比较深,可以定义为重要发展用户)
# 2  重要价值用户 (M值较大.R值较大)
# 1  一般挖掘用户 (R值较大,M值居中)
show_features(centers)

基于聚类算法(Kmeans)对电商用户做分群处理

# kmeans算法,其实就是在找相似程度(欧式距离)比较高的一类群体
# 存在大小列的问题,否则认为的干预了变量的影响力度

# 这个时候需要统一量纲
# 量纲统一的方法之一: 区间缩放法(列方向的缩放)

data = np.random.randint(110, size=(10))
data
array([2, 6, 5, 7, 8, 4, 8, 4, 5, 5])
data - data.min() / (data.max() - data.min())
array([1.66666667, 5.66666667, 4.66666667, 6.66666667, 7.66666667,
3.66666667, 7.66666667, 3.66666667, 4.66666667, 4.66666667])
data1 = np.random.randint(11000, size=(10))
data1 - data1.min() / (data1.max() - data1.min())
array([712.8766328, 310.8766328, 773.8766328, 432.8766328,  84.8766328,
309.8766328, 526.8766328, 218.8766328, 178.8766328, 613.8766328])
# 都是属于0-1之间的范围,可以缩放到相同量级的影响,这样我们就缩小列的大小对结果的影响

def minMaxScaller(data):
    return (data - data.min()) / (data.max() - data.min())

minMaxScaller(data)
array([0.        , 0.66666667, 0.5       , 0.83333333, 1.        ,
0.33333333, 1. , 0.33333333, 0.5 , 0.5 ])
minMaxScaller(data1)
array([0.91146589, 0.32801161, 1.        , 0.50507983, 0.        ,
0.32656023, 0.64150943, 0.19448476, 0.13642961, 0.76777939])
# 对数据进行特征缩放处理(无量纲化),缩放到同一个量级,处理掉量级不同对相似度评估的不良影响
from sklearn.preprocessing import MinMaxScaler

X.describe()

基于聚类算法(Kmeans)对电商用户做分群处理

# 现在对R,F,M做一个统一的量级
scaler = MinMaxScaler()
X_s = scaler.fit_transform(X)

X_s = pd.DataFrame(data=X_s, columns=X.columns)
X_s

X_s.min(), X_s.max()
(R    0.0
F 0.0
M 0.0
dtype: float64,
R 1.0
F 1.0
M 1.0
dtype: float64)
kmeans = KMeans(n_clusters=3)
kmeans.fit(X_s)
KMeans(n_clusters=3)
centers = kmeans.cluster_centers_

# 0 重要价值客户: R值较低,F值和M值最低
# 1 重要保持客户: R值很高,F,M值都比较低
# 2 一般保持客户: R值和F值较低,M值较高
show_features(centers)