本文是我学习机器学习的一篇学习笔记,
主要参考文章:运用K-Means聚类分析广告效果 感谢哈~
学习过程中遇到一些问题,故在此重新对代码做了整理
某企业,其主要的宣传获客手段是通过各个广告渠道投放广告,通过广告将用户引流至自己的企业官网。用户可以在该企业官网浏览及购买其产品及服务。
但是广告的渠道非常多,哪些渠道效果好,哪些效果不好,需要对广告效果进行分析,针对性地做广告效果测量和优化工作。
现有一份各类广告渠道90天内日均UV(独立访问量)、平均注册率、平均搜索率、访问深度、平均停留时长、订单转化率、投放时间、素材类型、广告类型、合作方式、广告尺寸和广告卖点等特征。
由于该企业广告渠道众多,我们希望将众多渠道按照重点特征分类,此时就可以使用聚类算法进行分类处理。请你通过聚类算法,将渠道分类,找出每类渠道的重点特征,为业务讨论和数据分析提供支持。
字段说明如下:
本案例主要使用Pandas、NumPy、Matplotlib、SKlearn模块进行数据分析。
import numpy as np
import pandas as pd
pd.set_option('display.max_columns', None) #显示所有列
pd.set_option('display.unicode.ambiguous_as_wide', True) #设置各列对齐
pd.set_option('display.unicode.east_asian_width', True)
pd.set_option('display.width', 180) #设置打印宽度
from sklearn.cluster import KMeans #KMeans库
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #支持中文
import seaborn as sns
from sklearn.preprocessing import MinMaxScaler #数据归一工具
from sklearn.preprocessing import OneHotEncoder #数据独热编码器
from sklearn.metrics import silhouette_score #导入轮廓系数指标
import matplotlib.colors as mcolors
import warnings
warnings.filterwarnings('ignore') # 忽视警告
print("类库引用成功!")
这里我们读入数据
df = pd.read_csv('./ad_performance.csv')
df.head()
print("\n查看原始数据")
df.head(2) # 打印输出前2条数据
print("\n打印原始数据摘要")
df.info()
print("\n打印原始数据基本描述性信息")
df.describe().round(2).T # 打印数据类型分布
print("\n缺失值审查")
df.isnull().any(axis=0) # 查看每一列是否具有缺失值
print("\n查看具有缺失值的行数")
df.isnull().sum().sort_values(ascending=False)
print("\n各列间的相关性分析:")
df2 = df.drop(['Unnamed: 0'], axis=1)
corr = df2.corr().round(2)
print(corr.T) # 打印原始数据相关性信息
print("\n打印热力图,相关性可视化展示")
sns.heatmap(corr,cmap='Reds',annot = True)
plt.show()
print("热力图打印完毕")
可以看到【平均停留时间】和【访问深度】相关性为0.72,可以删掉一列。其中【平均停留时间】与其他各列的相关性之和相比于【访问深度】更高,故我们可以删掉【平均停留时间】这一列。而刚好【平均停留时间】也存在2行缺失值。
print("\n删除相关性较强的列")
df2 = df.drop(['平均停留时间'],axis=1)
df2.head()
print("接下来我们字符型列进行独热编码\n")
print("查看字符型列取值")
cols_str_type = ["素材类型","广告类型","合作方式","广告尺寸","广告卖点"]
for x in cols_str_type:
data=df2[x].unique()
print("列【{0}】的取值有:\n{1}".format(x,data))
print("-·"*20)
print("\n字符串分类独热编码处理")
ohe_matrix = OneHotEncoder(sparse=False).fit_transform(df2[cols_str_type]) # 建立OneHotEncode对象
pd.DataFrame(ohe_matrix[:2]).head()
print("\n数据归一化")
df2.info()
cols_num_type = ['日均UV','平均注册率','平均搜索量','访问深度','订单转化率','投放总时间'] # 数值型列
sacle_matrix = df2.loc[:, cols_num_type] # 获得要转换的矩阵
data_scaled = MinMaxScaler().fit_transform(sacle_matrix) # MinMaxScaler标准化处理
pd.DataFrame(data_scaled.round(2)).head()
print("\n合并所有维度,得到新矩阵:X")
X = np.hstack((data_scaled, ohe_matrix))
pd.DataFrame(X.round(2)).head()
数据处理完,就可以带入模型进行训练了。
本步骤我们对上一步数据预处理后的数据进行建模,并找出最优k值(即判断:聚类成几个类别最合适)。
# 通过平均轮廓系数检验得到最佳KMeans聚类模型
score_list = list() # 用来存储每个K下模型的平局轮廓系数
silhouette_int = -1 # 初始化的平均轮廓系数阀值
for n_clusters in range(2, 8): # 遍历从2到8几个有限组
model_kmeans = KMeans(n_clusters=n_clusters) # 建立聚类模型对象
labels_tmp = model_kmeans.fit_predict(X) # 训练聚类模型
silhouette_tmp = silhouette_score(X, labels_tmp) # 得到每个K下的平均轮廓系数
if silhouette_tmp > silhouette_int: # 如果平均轮廓系数更高
best_k = n_clusters # 保存K将最好的K存储下来
silhouette_int = silhouette_tmp # 保存平均轮廓得分
best_kmeans = model_kmeans # 保存模型实例对象
cluster_labels_k = labels_tmp # 保存聚类标签
score_list.append([n_clusters, silhouette_tmp]) # 将每次K及其得分追加到列表
print('\n{:*^60}'.format('K值对应的轮廓系数:'))
print(np.array(score_list)) # 打印输出所有K下的详细得分
print('最优的K值是:{0} \n对应的轮廓系数是:{1}'.format(best_k, silhouette_int))
这一步我们将原始数据 df 和 聚类标签列 clusters 合并到一起,相当于为每一行数据打上聚类标签。
print("\n将原始数据与聚类标签整合:")
cluster_labels = pd.DataFrame(cluster_labels_k, columns=['clusters']) # 获得训练集下的标签信息
merge_data = pd.concat((df, cluster_labels), axis=1) # 将原始处理过的数据跟聚类标签整合
merge_data.head()
print("\n查看每个聚类类别下的样本量和样本占比:")
column_0 = merge_data.columns[0]
clustering_count = pd.DataFrame(merge_data[column_0].groupby(merge_data['clusters']).count()).T.rename({column_0: 'counts'}) # 计算每个聚类类别的样本量
clustering_ratio = (clustering_count / len(merge_data)).round(2).rename({'counts': 'percentage'}) # 计算每个聚类类别的样本量占比
print(clustering_count)
print("#"*30)
print(clustering_ratio)
所有的渠道被分为4各类别,
每个类别的样本量分别为:73、349、313、154
对应占比分别为:8%、39%、35%、17%
print("\n计算各个聚类类别内部最显著特征值:")
cluster_features = [] # 空列表,用于存储最终合并后的所有特征信息
for line in range(best_k): # 读取每个类索引
label_data = merge_data[merge_data['clusters'] == line] # 获得特定聚类类别的数据
part1_data = label_data.loc[:, cols_num_type] # 获得数值型数据特征
part1_desc = part1_data.describe().round(3) # 得到数值型特征的描述性统计信息
merge_data1 = part1_desc.iloc[2, :] # 得到数值型特征的均值
part2_data = label_data.loc[:, cols_str_type] # 获得字符串型数据特征
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) # 将每个类别下的数据特征追加到列表
# 输出完整的类别特征信息
cluster_pd = pd.DataFrame(cluster_features).T # 将列表转化为矩阵
print('\n{:*^60}'.format('每个类别主要的特征:'))
all_cluster_set = pd.concat((clustering_count, clustering_ratio, cluster_pd),axis=0) # 将每个聚类类别的所有信息合并
all_cluster_set
print("\n图形化输出:")
print("\n各类别数据预处理")
num_sets = cluster_pd.loc[cols_num_type, :].T.astype(np.float64) # 获取要展示的数据(数值型列)
num_sets_max_min = MinMaxScaler().fit_transform(num_sets) # 获得标准化后的数据
print("num_sets:",pd.DataFrame(num_sets))
print("num_sets_max_min:", pd.DataFrame(num_sets_max_min.round(2)))
# 画图
colors=list(mcolors.TABLEAU_COLORS.keys()) # matplotlib 绘图颜色自动选择
fig = plt.figure(figsize=(6,6)) # 建立画布
ax = fig.add_subplot(111, polar=True) # 增加子网格,注意polar参数
labels = np.array(merge_data1.index) # 设置要展示的数据标签
angles = np.linspace(0, 2 * np.pi, len(labels), endpoint=False) # 计算各个区间的角度
angles1 = angles;
angles = np.concatenate((angles, [angles[0]])) # 建立相同首尾字段以便于闭合
# 画雷达图
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=colors[i], label="第%d聚类簇"%(i)) # 画线
ax.fill(angles, data,alpha=0.5)
# 设置图像显示格式
ax.set_thetagrids(angles1 * 180 / np.pi, labels, fontproperties="Microsoft YaHei") # 设置极坐标轴
ax.set_title("各聚类类别显著特征对比", fontproperties="Microsoft YaHei") # 设置标题放置
ax.set_rlim(-0.2, 1.2) # 设置坐标轴尺度范围
plt.legend(loc="upper right" ,bbox_to_anchor=(1.2,1.0)) # 设置图例位置
plt.show()
聚类0:
这类渠道各方面特征都不明显,各个流量质量和流量数量的指标均处于“中等”层次。不突出但是均衡,可以考虑在各场景下在这个渠道投放广告。
聚类1:
这类广告媒体除了访问深度和投放时间较高,其他属性较低,因此这类广告媒体效果质量较差,并且占到39%,因此这类是主题渠道之一。业务部门要考虑他的实际投放价值。
聚类2:
这类广告媒体除了访问深度略差,在平均搜索量、日均UV、订单转化率等广告效果指标上表现良好,是一类综合效果较好的渠道。但是日均UV是短板,较低。无法给企业带来大量的流量以及新用户,这类广告的特质适合用户转化,尤其是有关订单的转化提升。
聚类3:
这类广告媒体的显著特征是日均UV和注册率较高,其“引流”和“拉新”效果好,可以在广告媒体中定位为引流角色。符合“广而告之”的诉求,适合“拉新”使用。