分群思维(四)基于KMeans聚类的广告效果分析

分群思维(四)基于KMeans聚类的广告效果分析

小P:小H,我手上有各个产品的多维数据,像uv啊、注册率啊等等,这么多数据方便分类吗

小H:方便啊,做个聚类就好了

小P:那可以分成多少类啊,我也不确定需要分成多少类

小H:只要指定大致的范围就可以计算出最佳的簇数,一般不建议过多或过少,2至4是最佳的

  • 导库
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.metrics import silhouette_score  # 导入轮廓系数指标
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder
  • 数据预处理

以下数据如果有需要的同学可关注公众号HsuHeinrich,回复【分群思维04】自动获取~

# 读取数据
raw_data = pd.read_table('ad_performance.txt', delimiter='\t')
raw_data.head()

image-20230206151545251

# 数据描述
raw_data.describe().round(2).T

image-20230206151610337

# 相关性分析
raw_data.corr().round(2).T 

image-20230206151648487

# 高相关性对基于距离的算法有显著影响,因此去掉一个
raw_data2 = raw_data.drop(['平均停留时间'], axis=1) 
# 字符串分类onehotencode处理
cols = ['素材类型','广告类型','合作方式','广告尺寸','广告卖点']
model_ohe = OneHotEncoder(sparse=False)
ohe_matrix = model_ohe.fit_transform(raw_data2[cols])
print(ohe_matrix[:2])
[[0. 1. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 1. 1. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0.
  0. 0. 0.]
 [0. 1. 0. 0. 1. 0. 0. 0. 0. 1. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0.
  0. 0. 0.]]
# 数值型数据标准化
sacle_matrix = raw_data2.iloc[:, 1:7]
model_scaler = MinMaxScaler()
data_scaled = model_scaler.fit_transform(sacle_matrix)
print(data_scaled.round(2))
[[0.   0.18 0.02 0.01 0.12 0.66]
 [0.01 0.1  0.03 0.01 0.01 0.62]
 [0.   0.06 0.05 0.01 0.01 0.1 ]
 ...
 [0.01 0.01 0.   0.   0.   0.72]
 [0.05 0.   0.   0.   0.   0.31]
 [0.   0.   0.   0.53 0.   0.62]]
# 合并所有维度
X = np.hstack((data_scaled, ohe_matrix))
  • 模型训练
# 通过平均轮廓系数检验得到最佳KMeans聚类模型
score_list = list() 
silhouette_int = -1 
for n_clusters in range(2, 5):  # 初始2至4个类别
    model_kmeans = KMeans(n_clusters=n_clusters) 
    labels_tmp = model_kmeans.fit_predict(X) 
    silhouette_tmp = silhouette_score(X, labels_tmp)  # 计算轮廓系数
    if silhouette_tmp > silhouette_int: 
        best_k = n_clusters  # 保存最大轮廓系数下的k
        silhouette_int = silhouette_tmp 
        best_kmeans = model_kmeans 
        cluster_labels_k = labels_tmp 
    score_list.append([n_clusters, silhouette_tmp])

print(np.array(score_list))  # 打印所有K的轮廓系数
print('Best K is:{0} with average silhouette of {1}'.format(best_k, silhouette_int))
[[2.         0.38655493]
 [3.         0.45864451]
 [4.         0.50209812]]
Best K is:4 with average silhouette of 0.5020981194788053
  • 模型结果
# 1. 将原始数据与聚类标签整合
cluster_labels = pd.DataFrame(cluster_labels_k, columns=['clusters'])  # 获取聚类标签
merge_data = pd.concat((raw_data2, cluster_labels), axis=1)

# 2. 计算每个聚类类别下的样本量和样本占比
clustering_count = pd.DataFrame(merge_data['ID'].groupby(merge_data['clusters']).count()).T.rename({'ID': 'counts'})  # 计算每个聚类类别的样本量
clustering_ratio = (clustering_count / len(merge_data)).round(2).rename({'counts': 'percentage'})  # 计算每个聚类类别的样本量占比

# 3. 计算各个聚类类别内部最显著特征值
cluster_features = []  # 空列表,用于存储最终合并后的所有特征信息
for line in range(best_k):  # 读取每个类索引
    label_data = merge_data[merge_data['clusters'] == line]  # 获得特定类的数据

    part1_data = label_data.iloc[:, 1:7]  # 获得数值型数据特征
    part1_desc = part1_data.describe().round(3)  # 得到数值型特征的描述性统计信息
    merge_data1 = part1_desc.iloc[1, :]  # 得到数值型特征的均值

    part2_data = label_data.iloc[:, 7:-1]  # 获得字符串型数据特征
    part2_desc = part2_data.describe(include='all')  # 获得字符串型数据特征的描述性统计信息
    merge_data2 = part2_desc.iloc[2, :]  # 获得字符串型数据特征的最频繁值

    merge_line = pd.concat((merge_data1, merge_data2), axis=0)  # 将数值型和字符串型典型特征沿行合并
    cluster_features.append(merge_line)  # 将每个类别下的数据特征追加到列表
# 4. 输出完整的类别特征信息
cluster_pd = pd.DataFrame(cluster_features).T  # 将列表转化为矩阵
print('{:*^60}'.format('Detailed features for all clusters:'))
all_cluster_set = pd.concat((clustering_count, clustering_ratio, cluster_pd),axis=0)  # 将每个聚类类别的所有信息合并
print(all_cluster_set)
************Detailed features for all clusters:*************
                  0        1        2        3
counts          349      313      154       73
percentage     0.39     0.35     0.17     0.08
日均UV        300.205  572.521  613.836  1401.53
平均注册率         0.001    0.001    0.003    0.001
平均搜索量         0.016    0.051     0.02    0.033
访问深度           2.27    2.145     2.19    1.727
订单转化率         0.002    0.004    0.003    0.002
投放总时间         15.35   17.125   15.682   15.603
素材类型            jpg      swf      jpg      swf
广告类型             横幅      不确定   banner     tips
合作方式            cpc      roi      cpc      cpm
广告尺寸         600*90   600*90  308*388  450*300
广告卖点             直降       打折       满减       打折
  • 通过雷达图观察分类结果
# 1. 各类别数据预处理
num_sets = cluster_pd.iloc[:6, :].T.astype(np.float64)  # 获取要展示的数据
num_sets_max_min = model_scaler.fit_transform(num_sets)  # 获得标准化后的数据
# 2. 画布基本设置
fig = plt.figure(figsize=(6,6))  # 建立画布
ax = fig.add_subplot(111, polar=True)  # 增加子网格,注意polar参数
labels = np.array(merge_data1.index)  # 设置要展示的数据标签
cor_list = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']  # 定义不同类别的颜色
angles = np.linspace(0, 2 * np.pi, len(labels), endpoint=False)  # 计算各个区间的角度
angles = np.concatenate((angles, [angles[0]]))  # 建立相同首尾字段以便于闭合
labels = np.concatenate((labels,[labels[0]]))   # 新版本增加,对labels进行封闭
# 3. 画雷达图
for i in range(len(num_sets)):  # 循环每个类别
    data_tmp = num_sets_max_min[i, :]  # 获得对应类数据
    data = np.concatenate((data_tmp, [data_tmp[0]]))  # 建立相同首尾字段以便于闭合
    ax.plot(angles, data, 'o-', c=cor_list[i], label=i)  # 画线
# 4. 设置图像显示格式
ax.set_thetagrids(angles * 180 / np.pi, labels, fontproperties="SimHei")  # 设置极坐标轴
ax.set_title("各聚类类别显著特征对比", fontproperties="SimHei")  # 设置标题放置
ax.set_rlim(-0.2, 1.2)  # 设置坐标轴尺度范围
plt.legend(loc=0)  # 设置图例位置
plt.show()

output_17_0

从雷达图我们发现四个各类别在6个数字特征上具有较大差异,0类更偏向访问深度,3类更偏向日均uv,2和3类在多个指标表现都较好,但也存在差异。

总结

聚类能很好的解决多维数据的分类问题,雷达图能很好的观察差异。当然聚类的方法有很多,例如K均值的变体k-means++、bi-kmeans、kernel k-means,密度聚类的DBSCAN,层次聚类的Agglomerative等等

共勉~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值