基于聚类算法(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')
# 这个聚类中心代表着这一类群体代表的特征,不光光指的是一个点
# 样本集 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 fit之后,就已经知道了对于训练的样本集聚类的结果
# 本质就是predict(x)的结果
kmeans.labels_
中国足球水平分析
zoo = pd.read_table('AsiaZoo.txt', header=None, sep=',')
zoo.columns = ['国家', '2006世界杯', '2010世界杯', '2007世界杯']
zoo
我们对于特征的选取,需要根据业务目标,选择有效字段,在这里我们是研究球队的水平,所以特征应该去除那些对水平有影响的字段,所以我们这里只选择三次比赛的成绩排名。
注:建模是为了解决业务逻辑上的问题,当我们对某些指标取不到量化的字段的时候,我们就需要埋点操作了,并且我们埋点的逻辑也应该正确,获取用户的信息不能有偏差。
X = zoo[['2006世界杯', '2010世界杯', '2007世界杯']]
# 把球队划分为3个不同的水平
kmeans = KMeans(n_clusters=3)
# 训练模型
kmeans.fit(X)kmeans.predict(X)
kmeans.labels_
# 两步变为一步
y_ = kmeans.fit_predict(X)
# 虽然标签变了,但是本质时一样的,还是归类为一类
y_# 保存结果
zoo['y'] = y_for k, v in zoo.groupby('y').groups.items():
print(zoo.loc[v, '国家'])
# 聚类中心可以描述每一组数据的平均水平
# 经常也会使用聚类中心做一些可视化的说明
kmeans.cluster_centers_centers = pd.DataFrame(data=kmeans.cluster_centers_, columns=X.columns)
map_dict = {
0: '中',
1: '差',
2: '强'
}
zoo['水平'] = zoo.y.map(map_dict)
zoo
聚类算法使用过程当中常见的问题
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, 作用是随机后的结果永远保持一样的# 解释随机种子的作用,种子可以限定随机的策略,不同的种子得到的随机结果不同,相同的种子得到的结果相同
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)# 对比引入偏差后数据的分布
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(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')# 结论:数据偏差对我们建模的影响是巨大的
# 原则上,我们建模就是想进各种办法尽可能缩小数据噪声对模型的影响
# 如果数据质量较好的情况下,模型都很好,但是实际情况下不是这样的,而且模型准确度的波动也是非常大的
# 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(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')# 标准差不同,也会影响预测的结果
# 4. 样本不均衡
X, y = make_blobs(n_samples=1500, n_features=2, centers=3)
pd.Series(y).value_counts()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(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')# 所有的建模过程中,此类问题都有影响(普遍性问题)
# 总结:
# 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(n_clusters=3)
y_ = kmeans.fit_predict(X)
# 计算每一个样本点的轮廓系数:我这只显示前五行
silhouette_samples(X, y)# 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_imgarray([[[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)a = kmeans.cluster_centers_/255
sns.palplot(a)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)order.drop(labels=['品牌名称'], axis=1, inplace=True)
order.head()# 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_timeTimestamp('2019-06-30 22:46:22.511000')(order['付款日期'].max() - order['付款日期'].min())
Timedelta('180 days 22:28:23.511000')R = end_time - order['付款日期']
R0 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)
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: int64plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.figure(figsize=(5, 5))
order['订单状态'].value_counts().plot(kind='pie', autopct='%.2f%%')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# 计算M值
# 每一个用户的付款总额
order.head()m_value = order.groupby('买家昵称')['实付金额'].sum()
m_value.name = 'M'
M = pd.DataFrame(data=m_value)
M# 汇总RMF三个值
temp = pd.merge(left=R, right=F, left_index=True, right_index=True)
temptotal = pd.merge(left=temp, right=M, left_index=True, right_index=True)
total# 基于这三个维度,将每个维度分为高低两种情况,我们构建了一个三维的坐标系
# 确定阈值,一定要观察数据本身的分布情况
# (直方图) kde
# 平均值 或 中位数(如果数据有异常时,经常会使用,否则使用平均值)
sns.histplot(data=total, x='R')sns.histplot(data=total, x='F')
# 说明右侧是有异常数据的,某些用户的消费次数比较多total.F.value_counts()
# 几乎可以确认只要有复购行为的用户都属于高价值用户1 23367
2 1795
3 217
4 33
5 5
15 1
7 1
6 1
Name: F, dtype: int64sns.histplot(data=total, x='M')
# 我们先之观察1000以内的
temp = total.loc[total.M < 1000]
sns.histplot(data=temp, x='M')# 说明从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# 重要发展客户(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()total['VALUE'] = total.R_V * 100 + total.F_V * 10 + total.M_V * 1
total# 处理映射关系
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()# 后面的丢失了精度,所以我们应该从原始字段开始做分析
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# 我们将我们的客户分为几个有特点的群体
# 一般需要考虑三个结果:
# 现在的聚类中心能描述用户特征吗?能不能有可视化的方案?能推行下去吗,符合业务的需求吗?
# 现在的结果有很多问题
# 聚类数据中有异常没有处理
# 聚类结果,辨识度并不高,可视化方案
centers = kmeans.cluster_centers_
centersarray([[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(0, 2 * 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(0, 2 * np.pi, 3, endpoint=False), ['R', 'F', 'M'])
plt.legend()
show_features(centers)# 观察聚类结果发现:
# 1.数据簇之间没有辨识度可言
# 2.异常值明显
X# 根据数据分布,M值的主要消费区间在0-300之间,所以如果高于这个区间的用户,我们可以使用统一的300填充
# 因为我们的目标就是区分他是高价值还是低价值
sns.displot(X.loc[X.M < 400])X.loc[X.M >= 300, 'M'] = 300
# 异常值有几种处理方式(过滤,填充)
# 1.99分位数过滤
# 2.3std过滤
# 3.离群点检测
sns.displot(X.loc[X.M])# 关于F字段用户的异常值的处理,使用4来填充所有高于4次的购买次数
sns.distplot(X.F)X.loc[X.F >= 3, 'F'] = 3
sns.distplot(X.F)# 为什么处理异常?
# 建模类的需求:异常数据必须解决(往往找的是公共性的特点)
# 统计类需求:异常数据可以不解决
# cluster_centers_这个数据就是由平均值得来的,所以聚类分析,必须要做异常数据的过滤
# 平均值会受到异常值的影响,所以异常值必须处理
# 异常处理之后,再聚类分析
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)KMeans(n_clusters=3)centers = kmeans.cluster_centers_
centersarray([[ 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算法,其实就是在找相似程度(欧式距离)比较高的一类群体
# 存在大小列的问题,否则认为的干预了变量的影响力度
# 这个时候需要统一量纲
# 量纲统一的方法之一: 区间缩放法(列方向的缩放)
data = np.random.randint(1, 10, size=(10))
dataarray([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(1, 1000, 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()# 现在对R,F,M做一个统一的量级
scaler = MinMaxScaler()
X_s = scaler.fit_transform(X)
X_s = pd.DataFrame(data=X_s, columns=X.columns)
X_sX_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)