K-means聚类模型是一种经典的无监督学习算法,用于将一组数据点划分为K个不同的簇。其核心目标是使得每个数据点与其所属簇的质心(聚类中心)之间的距离之和最小,以此来体现簇内数据点的相似性 。K-means算法的工作原理主要包括以下几个步骤:
1. 初始化:选择K个初始聚类中心,这通常通过随机选择数据集中的K个点来实现。
2. 分配:将每个数据点分配给最近的聚类中心,形成K个簇。
3. 更新:重新计算每个簇的聚类中心,即簇内所有点的均值。
4. 迭代:重复分配和更新步骤,直到满足终止条件,如聚类中心的变化小于某个阈值或达到预设的迭代次数。
K-means算法在多个领域有广泛应用,包括图像处理中的图像分割和颜色量化 、市场分析中客户细分和产品推荐 、文本挖掘中的文档聚类和主题识别 ,以及生物信息学中的基因表达数据聚类 。
在Python中,可以使用sklearn库中的KMeans类来实现K-means算法。通过平均轮廓系数(Silhouette Coefficient)来确定最佳的KMeans聚类模型的K值。轮廓系数是一个介于-1到1之间的数值,用来衡量聚类效果的好坏。值越大,表示聚类效果越好。通过确定最佳的聚类数K,可以有效地对数据进行聚类,并利用matplotlib库将聚类结果进行可视化 。
接下来将对一个关于不同的投放广告渠道的效果和性质的数据集进行K-means聚类,从而找出每类渠道的重点特征。
一、数据预处理
数据下载和观看入口:数据集_机器学习 - 飞书云文档 (feishu.cn)
假如公司投放广告的渠道很多,每个渠道的客户性质也可能不同,效果可能会有差异。现在需要对广告效果分析实现有针对性的广告效果测量和优化工作。
本案例,通过各类广告渠道90天内额日均UV,平均注册率、平均搜索率、访问深度、平均停留时长、订单转化率、投放时间、素材类型、广告类型、合作方式、广告尺寸和广告卖点等特征,将渠道分类,找出每类渠道的重点特征,为加下来的业务讨论和数据分析提供支持。
数据维度概况
除了渠道唯一标识,共12个维度,889行,有缺失值,有异常值。
数据13个维度介绍
1、渠道代号:渠道唯一标识
2、日均UV:每天的独立访问量
3、平均注册率=日均注册用户数/平均每日访问量
4、平均搜索量:每个访问的搜索量
5、访问深度:总页面浏览量/平均每天的访问量
6、平均停留时长=总停留时长/平均每天的访问量
7、订单转化率=总订单数量/平均每天的访客量
8、投放时间:每个广告在外投放的天数
9、素材类型:'jpg' 'swf' 'gif' 'sp'
10、广告类型:banner、tips、不确定、横幅、暂停
11、合作方式:'roi' 'cpc' 'cpm' 'cpd'
12、广告尺寸:'14040' '308388' '450300' '60090' '480360' '960126' '900120' '390270'
13、广告卖点:打折、满减、满赠、秒杀、直降、满返
首先导入所需的库:
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler,OneHotEncoder
from sklearn.metrics import silhouette_score # 导入轮廓系数指标
from sklearn.cluster import KMeans # KMeans模块
## 设置属性防止中文乱码
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
再导入数据:
raw_data = pd.read_csv(r'./ad_performance.csv')
raw_data.head()
数据样貌如下:
我们先探究数值变量之间的相关性,进行相关性可视化展示:
# 相关性可视化展示
import seaborn as sns
corr = raw_data.corr().round(2)
sns.heatmap(corr,cmap='Reds',annot = True)
得到以下相关性表:
可以看到,“访问深度”和“平均停留时间”相关性比较高,相关性高说明两个变量在建立模型的时候,作用是一样或者效果是一样的,可以考虑组合或者删除其一。
# 删除平均平均停留时间列
raw_data2 = raw_data.drop(['平均停留时间'],axis=1)
我们再将数值变量进行标准化:
# 数据标准化
sacle_matrix = raw_data2.iloc[:, 1:7] # 获得要转换的矩阵
model_scaler = MinMaxScaler() # 建立MinMaxScaler模型对象
data_scaled = model_scaler.fit_transform(sacle_matrix) # MinMaxScaler标准化处理
-
建立MinMaxScaler模型对象:
model_scaler = MinMaxScaler()
:这里创建了一个MinMaxScaler
对象。MinMaxScaler
是scikit-learn库中的一个数据预处理工具,用于将数据缩放到一个固定范围,通常是[0, 1]。
-
标准化处理:
data_scaled = model_scaler.fit_transform(sacle_matrix)
:这个步骤是核心,其中fit_transform
方法首先使用提供的数据集来计算每个特征的缩放参数(最小值和最大值),然后使用这些参数来转换数据。这个方法将原始数据sacle_matrix
缩放到[0, 1]的范围内。
接下来处理类别变量,进行独热编码:
# 字符串分类独热编码处理
cols = ['素材类型','广告类型','合作方式','广告尺寸','广告卖点']
model_ohe = OneHotEncoder(sparse=False) # 建立OneHotEncode对象
ohe_matrix = model_ohe.fit_transform(raw_data2[cols]) # 直接转换
# 用pandas的方法
ohe_matrix1=pd.get_dummies(raw_data2[cols])
ohe_matrix1.head(5)
可将类别变量转为如下形式:
数据处理完,我们将独热编码的数据和标准化转化后的数据合并,这样就把常规数据通过清洗、转换、规约、聚合、抽样等方式变成机器学习可以识别或者提升准确度的数据:
# # 合并所有维度
X = np.hstack((data_scaled, ohe_matrix))
数据处理完,就可以带入模型进行训练了。
二、建立K-means聚类模型
# 目的是通过平均轮廓系数(Silhouette Coefficient)来确定最佳的KMeans聚类模型的K值。轮廓系数是一个介于-1到1之间的数值,用来衡量聚类效果的好坏。值越大,表示聚类效果越好。下面是代码的逐行解释:
# 通过平均轮廓系数检验得到最佳KMeans聚类模型
score_list = list() # 用来存储每个K下模型的平局轮廓系数
silhouette_int = -1 # 初始化的平均轮廓系数阀值
for n_clusters in range(2, 8): # 遍历从2到5几个有限组
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(np.array(score_list)) # 打印输出所有K下的详细得分
print('最优的K值是:{0} \n对应的轮廓系数是:{1}'.format(best_k, silhouette_int))
这段代码是用于确定最佳KMeans聚类模型K值。这个过程中,使用了平均轮廓系数(Silhouette Coefficient)作为评估聚类效果的指标。平均轮廓系数是一个介于-1到1之间的数值,值越大表示聚类效果越好。
代码解释:
1. 初始化:
- `score_list = list()`:创建一个列表,用于存储每个K值下的平均轮廓系数。
- `silhouette_int = -1`:初始化平均轮廓系数的阈值为-1,用于比较后续计算的轮廓系数。
2. 遍历不同的K值:
- `for n_clusters in range(2, 8)`:遍历K值从2到7(包括2和7)。
- `model_kmeans = KMeans(n_clusters=n_clusters)`:对于每个K值,创建一个KMeans模型对象。
3. 训练和评估模型:
- `labels_tmp = model_kmeans.fit_predict(X)`:使用当前K值训练模型,并预测聚类标签。
- `silhouette_tmp = silhouette_score(X, labels_tmp)`:计算当前K值下的平均轮廓系数。
4. 选择最佳K值:
- `if silhouette_tmp > silhouette_int`:如果当前的平均轮廓系数高于之前记录的最大值,则更新最佳K值和对应的平均轮廓系数。
- `best_k = n_clusters`:更新最佳K值。
- `silhouette_int = silhouette_tmp`:更新平均轮廓系数的阈值。
- `best_kmeans = model_kmeans`:保存当前的最佳KMeans模型实例。
- `cluster_labels_k = labels_tmp`:保存当前的最佳聚类标签。
5. 存储结果:
- `score_list.append([n_clusters, silhouette_tmp])`:将当前K值和对应的平均轮廓系数添加到`score_list`中。
6. 输出结果:
- `print(np.array(score_list))`:打印输出所有K值及其对应的平均轮廓系数。
- `print('最优的K值是:{0} \n对应的轮廓系数是:{1}'.format(best_k, silhouette_int))`:打印输出最佳K值和对应的平均轮廓系数。
得到结果如下:
三、聚类结果特征分析与展示
通过上面模型,我们其实给每个观测(样本)打了个标签clusters,即他属于4类中的哪一类:
# 将原始数据与聚类标签整合
cluster_labels = pd.DataFrame(cluster_labels_k, columns=['clusters']) # 获得训练集下的标签信息
merge_data = pd.concat((raw_data2, cluster_labels), axis=1) # 将原始处理过的数据跟聚类标签整合
merge_data.head()
便可得到聚类后的结果:
再计算每个类别下的样本数量和占比:
# 计算每个聚类类别下的样本量和样本占比
clustering_count = pd.DataFrame(merge_data['渠道代号'].groupby(merge_data['clusters']).count()).T.rename({'渠道代号': 'counts'}) # 计算每个聚类类别的样本量
clustering_ratio = (clustering_count / len(merge_data)).round(2).rename({'counts': 'percentage'}) # 计算每个聚类类别的样本量占比
print(clustering_count)
print("#"*30)
print(clustering_ratio)
结果如下:
然后找出每个类别内部最显著的特征:
# 计算各个聚类类别内部最显著特征值
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[2, :] # 得到数值型特征的均值
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) # 将每个类别下的数据特征追加到列表
# 输出完整的类别特征信息
cluster_pd = pd.DataFrame(cluster_features).T # 将列表转化为矩阵
all_cluster_set = pd.concat((clustering_count, clustering_ratio, cluster_pd),axis=0) # 将每个聚类类别的所有信息合并
all_cluster_set
这段代码用于计算每个聚类类别内部最显著的特征值。这个过程通常用于分析聚类结果,以了解每个聚类内部的主要特征。
代码解释:
-
初始化:
cluster_features = []
:创建一个空列表,用于存储每个聚类类别的特征信息。
-
遍历每个聚类:
for line in range(best_k)
:遍历最佳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[2, :]
:提取数值型特征的均值。
-
处理字符串型特征:
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)
:将合并后的特征信息追加到cluster_features
列表。
-
输出结果:
cluster_pd = pd.DataFrame(cluster_features).T
:将cluster_features
列表转换为DataFrame,并转置以获得更好的可读性。all_cluster_set = pd.concat((clustering_count, clustering_ratio, cluster_pd), axis=0)
:将每个聚类类别的所有信息合并,包括聚类计数、比例和特征信息。
便可得到如下结果:
从案例结果来看,所有的渠道被分为4个类别,每个类别的样本量分别为:154、313、349 、73,对应占比分别为:17%、35%、39%、8%。
类别1(索引为2类的渠道) 这类广告媒体除了访问深度和投放时间较高,其他属性较低,因此这类广告媒体效果质量较差,并且占到39%,因此这类是主题渠道之一。 业务部门要考虑他的实际投放价值。
类别2(索引为1类的渠道) 这类广告媒体除了访问深度略差,在平均搜索量、日均UV、订单转化率等广告效果指标上表现良好,是一类综合效果较好的渠道。 但是日均UV是短板,较低。无法给企业带来大量的流量以及新用户,这类广告的特质适合用户转化,尤其是有关订单的转化提升。
类别3(索引为0类的渠道) 这类广告媒体的显著特征是日均UV和注册率较高,其“引流”和“拉新”效果好,可以在广告媒体中定位为引流角色。 符合“广而告之”的诉求,适合“拉新”使用。
类别4(索引为3类的渠道) 这类渠道各方面特征都不明显,各个流量质量和流量数量的指标均处于“中等”层次。不突出但是均衡,考虑在各场景下可以考虑在这个渠道投放广告。
以上就是对一个关于不同的投放广告渠道的效果和性质的数据集进行K-means聚类的详细过程。
点下关注,分享更多有关AI,数据分析和量化金融方面的实用教程和实战项目。