Kmeans 聚类数据任务实现与分析

摘要:作为无监督聚类算法中的代表——K均值聚类(Kmeans)算法,该算法的主要作用是将相似的样本自动归到一个类别中。Kmeans算法是最常用的聚类算法,主要思想是:在给定K值和K个初始类簇中心点的情况下,把每个点(即数据记录)分到离其最近的类簇中心点所代表的类簇中,所有点分配完毕之后,根据一个类簇内的所有点重新计算该类簇的中心点(取平均值),然后再迭代的进行分配点和更新类簇中心点的步骤,直至类簇中心点的变化很小,或者达到指定的迭代次数。

一、问题介绍

本案例,通过各类广告渠道90天内额日均UV,平均注册率、平均搜索率、访问深度、平均停留时长、订单转化率、投放时间、素材类型、广告类型、合作方式、广告尺寸和广告卖点等特征,将渠道分类,找出每类渠道的重点特征,为业务讨论和数据分析提供支持。
数据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. 广告卖点:打折. 满减. 满赠. 秒杀. 直降. 满返

要求:
完成缺失值处理
完成相关性分析
完成数据编码与标准化
完成建立KMeans聚类模型
对模型结果进行分析总结
聚类分析可视化展示(选做)
输出聚类结果result.csv

二、结题步骤

2.1导入项目所用到的包

import pandas as pd
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder,LabelEncoder  # 预处理
from sklearn.cluster import KMeans  # 聚类算法
from sklearn.metrics import silhouette_score  # 用于评估度量的模块
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
# 设置显示格式
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
pd.set_option('max_colwidth', 30)
# 设置图像的字体
matplotlib.rc("font",family="STXingkai")
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']

2.2导入数据并查看

# 获取到数据
data = pd.read_csv('ad_performance.csv',index_col=0)
print(data)

在这里插入图片描述

2.3对数据进行审查,看是否有缺失值

# 对数据进行审查:是否有缺失值
print('{:*^60}'.format('数据样本:统计描述'))
print(data.describe().round(4).T)

在这里插入图片描述
从数据审查可以看出:
1.UV的数据波动很大,说明不同渠道差异是很明显的。但是差异并不一定是异常值,所以一般不作为异常值处理。
2.平均注册率,平均搜索量,订单转化率多个统计量为0,考虑到极大值本身就很小,说明数据本身就很小,符合实际情况,所以是正常的。

2.4填充缺失值

# 对缺失值的填充(均值)
print('{:*^60}'.format('缺失值:填充法'))
print(data[data.isna().values == True])
# print(data.isna().values)
data = data.fillna(419.77)
print(data[data.isna().values == True])

在这里插入图片描述

2.5相关性分析
在使用K-Means进行聚类分析时,该算法会计算数据与中心点之间的欧氏距离,两个高相关性的变量会使算法重复计算高相关特征这会夸大影响,影响最终的聚类结果,因此需要合并高相关性变量。

#相关性分析
print('{:*^60}'.format('相关性分析'))
print(data.corr().round(4).T)
# 生成相关性统计表格
#pd.DataFrame(data.corr().round(4).T).to_excel('result.xlsx')
data = data.drop(['平均停留时间'], axis=1)
print(data.columns)
print("**********************")
print(data.corr().round(4).T)

在这里插入图片描述

2.6数据标准化

#数据标准化
matrix = data.iloc[:, 1:7]  #获得要转换的矩阵
print(matrix)
#print("****************")
min_max_model = MinMaxScaler()
data_rescaled = min_max_model.fit_transform(matrix)
print('{:*^60}'.format('数据标准化'))
print(data_rescaled.round(2))

在这里插入图片描述

2.7数字特征化,即将字符特征转化为标志位(0、1)

# 特征数字化
print(data.iloc[:, 7:12])
onehot_mode = OneHotEncoder(sparse=False)
le=LabelEncoder()
y=data.iloc[:,7:12]
data_le=[]
for L in y.columns:
    y[L]=le.fit_transform(y[L])
    data_le.append(y[L])
print(data_le)
data_ohe = onehot_mode.fit_transform(y)
print('{:*^60}'.format('特征数字化'))
print(data_ohe)
print(data_ohe.shape)

在这里插入图片描述

2.8数据合并

# 数据合并
print('{:*^60}'.format('数据维度合并'))
data_matrix = np.hstack((data_rescaled, data_ohe))
for i in data_matrix:
    print(i.round(2))
print(data_matrix)
print(data_matrix.shape)

在这里插入图片描述

2.9建立KMeans聚类模型

# KMeans建模:基于平均轮廓系数,找到最佳K值
print('{:*^60}'.format('KMeans建模:基于平均轮廓系数'))
score_list = []
max_score = -1
for k in range(2, 6):  # 2,3,4,5
    kmeans_model = KMeans(n_clusters=k)  # 建模
    kmeans_temp = kmeans_model.fit_predict(data_matrix)  # 计算点距离
    #print(kmeans_temp)
    score = silhouette_score(data_matrix, kmeans_temp)  # 得到每个K下的平均轮廓系数
    # 获取最佳k值
    if score > max_score:  # 如果平均轮廓系数更高
        max_score = score  # 保存更高的系数值
        best_k = k  # 保存最佳的k值
        labels_temp = kmeans_temp  # 保存标签数据
        print(k, score)
    score_list.append([k, score])  # 存每一次的k值和对应的平均轮廓系数
print('{:*^60}'.format('所有的k值以及对应平均轮廓系数'))
print(score_list)
print('最佳K值:', best_k)

在这里插入图片描述
得到最佳K值为4

2.10聚类结果分析

#聚类结果分析
print('{:*^60}'.format('聚类结果分析'))
#1.合并数据与聚类标签
cluster_labels = pd.DataFrame(labels_temp, columns=['clusters'])  # 将聚类标签转化为df
merge_data = pd.concat((data, cluster_labels), axis=1)  # 整合原始数据与聚类标签
#2.各聚类下的样本量:select count(渠道标识) from table group by 聚类标签
cluster_counts = pd.DataFrame(merge_data['渠道代号'].groupby(merge_data['clusters'])
                              .count()).T.rename({'渠道代号': 'counts'})
print(cluster_counts)

在这里插入图片描述
渠道分类4个类别,样本数据分别为349、313、73、154,其中第三类样本量较少

2.11查看各聚类的占比

# 各聚类下的样本占比
cluster_percents = (cluster_counts / len(data)).round(3).rename({'counts': 'percentage'})
print(cluster_percents)

在这里插入图片描述

2.12数据合并,生成csv文件

#数据合并
cluster_pd = pd.DataFrame(features).T
all_cluster_pd = pd.concat((cluster_counts, cluster_percents, cluster_pd), axis=0)
#print(all_cluster_pd)
pd.DataFrame(all_cluster_pd).to_csv('result.csv')

在这里插入图片描述

2.13可视化分析数值特征对比

# 数值特征的对比分析:绘制雷达图
#1.获取各簇/类/集群的数值特征均值、并且标准化(Max-Min归一化,0~1)
print('{:*^60}'.format('数值特征的对比分析:绘制雷达图'))
nums_data = cluster_pd.iloc[:6, :].T.astype(np.float64)  # 获取数据并转换为浮点数
nums_min_max = min_max_model.fit_transform(nums_data)  # 获取标准化(归一化)后的数据
print(nums_min_max.round(4))

# 2.绘制画布、准备数据:x轴角度、y轴数据、类别对应颜色
fig = plt.figure()  # 创建一个画布
ax = fig.add_subplot(111, polar=True)  # 创建子网格:正中央、极坐标系
angles = np.linspace(0, 2 * np.pi, 6, endpoint=False)  # 计算角度
angles = np.concatenate((angles, [angles[0]]))  # 完成了对于x轴的设置,并且最后一个值=第一个值,以闭合图形
colors = ['b', 'y', 'r', 'g'] # 设置颜色
labels = p1_data.columns.tolist() # 获取数字类特征的列名
labels = np.concatenate((labels, [labels[0]])) # 对lables进行闭合

# 3.绘制各簇对应的点线图
# y轴的设置:0 1 2 3
for i in range(len(nums_min_max)):
    temp_list = nums_min_max[i]  # 获得对应簇数值特征数据
    temp = np.concatenate((temp_list, [temp_list[0]]))  # 完成闭合
    ax.plot(angles, temp, 'o-', color=colors[i], label=i)

# 4.添加说明标签、显示雷达图
ax.set_thetagrids(angles * 180 / np.pi, labels)  # 设置极坐标
ax.set_rlim(-0.2, 1.2)  # 设置半径刻度
plt.title("数值特征对比分析")  # 设置标题
plt.legend()  # 类说明标签
plt.show()

在这里插入图片描述

三、聚类结果分析

聚类1(标签0):欠佳
除了访问深度较高外,其他特征都属于极低的层次,因此广告媒体效果质量欠佳,且占比达39%,属主体渠道
建议:低性价比,重点考虑投放价值

聚类2(标签1):综合效果好
除了平均注册率较差,在平均搜索量、日均UV、订单转化率等广告效果指标的表现都不错,是一类综合效果比较好的媒体类
建议:适用于各种场景下的广告投放

聚类3(标签2):引流
日均UV与平均搜索量的表现比较突出,尤其是日均UV,但其他各方面的特征都不明显,符合引流类角色定位
建议:符合广告本身诉求,适合拉新场景使用

聚类4(标签3):转化高
在中等的日均UV表现下,有较高的平均注册率、访问深度以及订单转化率,可见该渠道整体转化率较高
建议:高转化,高质量,重点提升订单转化

附源码和广告数据csv文件:

import pandas as pd
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder,LabelEncoder  # 预处理
from sklearn.cluster import KMeans  # 聚类算法
from sklearn.metrics import silhouette_score  # 用于评估度量的模块
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
# 设置显示格式
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
pd.set_option('max_colwidth', 30)
# 设置图像的字体
matplotlib.rc("font",family="STXingkai")
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']

# 获取到数据
data = pd.read_csv('ad_performance.csv',index_col=0)
print(data)

# 对数据进行审查:是否有缺失值
print('{:*^60}'.format('数据样本:统计描述'))
print(data.describe().round(4).T)

# 对缺失值的填充(均值)
print('{:*^60}'.format('缺失值:填充法'))
print(data[data.isna().values == True])
# print(data.isna().values)
data = data.fillna(419.77)
print(data[data.isna().values == True])

#相关性分析
print('{:*^60}'.format('相关性分析'))
print(data.corr().round(4).T)
# 生成相关性统计表格
#pd.DataFrame(data.corr().round(4).T).to_excel('result.xlsx')
data = data.drop(['平均停留时间'], axis=1)
print(data.columns)
print("**********************")
print(data.corr().round(4).T)

#数据标准化
matrix = data.iloc[:, 1:7]  #获得要转换的矩阵
print(matrix)
#print("****************")
min_max_model = MinMaxScaler()
data_rescaled = min_max_model.fit_transform(matrix)
print('{:*^60}'.format('数据标准化'))
print(data_rescaled.round(2))

# 特征数字化
print(data.iloc[:, 7:12])
onehot_mode = OneHotEncoder(sparse=False)
le=LabelEncoder()
y=data.iloc[:,7:12]
data_le=[]
for L in y.columns:
    y[L]=le.fit_transform(y[L])
    data_le.append(y[L])
print(data_le)
data_ohe = onehot_mode.fit_transform(y)
print('{:*^60}'.format('特征数字化'))
print(data_ohe)
print(data_ohe.shape)

# 数据合并
print('{:*^60}'.format('数据维度合并'))
data_matrix = np.hstack((data_rescaled, data_ohe))
for i in data_matrix:
    print(i.round(2))
print(data_matrix)
print(data_matrix.shape)

# KMeans建模:基于平均轮廓系数,找到最佳K值
print('{:*^60}'.format('KMeans建模:基于平均轮廓系数'))
score_list = []
max_score = -1
for k in range(2, 6):  # 2,3,4,5
    kmeans_model = KMeans(n_clusters=k)  # 建模
    kmeans_temp = kmeans_model.fit_predict(data_matrix)  # 计算点距离
    #print(kmeans_temp)
    score = silhouette_score(data_matrix, kmeans_temp)  # 得到每个K下的平均轮廓系数
    # 获取最佳k值
    if score > max_score:  # 如果平均轮廓系数更高
        max_score = score  # 保存更高的系数值
        best_k = k  # 保存最佳的k值
        labels_temp = kmeans_temp  # 保存标签数据
        print(k, score)
    score_list.append([k, score])  # 存每一次的k值和对应的平均轮廓系数
print('{:*^60}'.format('所有的k值以及对应平均轮廓系数'))
print(score_list)
print('最佳K值:', best_k)

#聚类结果分析
print('{:*^60}'.format('聚类结果分析'))
#1.合并数据与聚类标签
cluster_labels = pd.DataFrame(labels_temp, columns=['clusters'])  # 将聚类标签转化为df
merge_data = pd.concat((data, cluster_labels), axis=1)  # 整合原始数据与聚类标签
#2.各聚类下的样本量:select count(渠道标识) from table group by 聚类标签
cluster_counts = pd.DataFrame(merge_data['渠道代号'].groupby(merge_data['clusters'])
                              .count()).T.rename({'渠道代号': 'counts'})
print(cluster_counts)

# 各聚类下的样本占比
cluster_percents = (cluster_counts / len(data)).round(3).rename({'counts': 'percentage'})
print(cluster_percents)
# 查看各聚类的特征,对数值类型查看均值,对文本类型查看众数
features = []
for label in range(best_k):
    label_data = merge_data[merge_data['clusters'] == label]

    # 4.数值类特征的均值
    p1_data = label_data.iloc[:, 1:7]  # 筛选出数值类特征
    p1_des = p1_data.describe().round(3)  # 获取描述性统计信息
    p1_mean = p1_des.iloc[1, :]  # 获取均值数据

    # 5.字符类特征的众数
    p2_data = label_data.iloc[:, 7:12]  # 筛选出字符类特征
    p2_des = p2_data.describe()  # 获取描述性统计信息
    p2_mode = p2_des.iloc[2, :]  # 获取频数最高的标签

    # 横向拼接2类不同特征的数据
    merge_line = pd.concat((p1_mean, p2_mode), axis=0)
    # 纵向拼接4类簇的统计数据
    features.append(merge_line)

#数据合并
cluster_pd = pd.DataFrame(features).T
all_cluster_pd = pd.concat((cluster_counts, cluster_percents, cluster_pd), axis=0)
#print(all_cluster_pd)
pd.DataFrame(all_cluster_pd).to_csv('result.csv')

# 数值特征的对比分析:绘制雷达图
#1.获取各簇/类/集群的数值特征均值、并且标准化(Max-Min归一化,0~1)
print('{:*^60}'.format('数值特征的对比分析:绘制雷达图'))
nums_data = cluster_pd.iloc[:6, :].T.astype(np.float64)  # 获取数据并转换为浮点数
nums_min_max = min_max_model.fit_transform(nums_data)  # 获取标准化(归一化)后的数据
print(nums_min_max.round(4))

# 2.绘制画布、准备数据:x轴角度、y轴数据、类别对应颜色
fig = plt.figure()  # 创建一个画布
ax = fig.add_subplot(111, polar=True)  # 创建子网格:正中央、极坐标系
angles = np.linspace(0, 2 * np.pi, 6, endpoint=False)  # 计算角度
angles = np.concatenate((angles, [angles[0]]))  # 完成了对于x轴的设置,并且最后一个值=第一个值,以闭合图形
colors = ['b', 'y', 'r', 'g'] # 设置颜色
labels = p1_data.columns.tolist() # 获取数字类特征的列名
labels = np.concatenate((labels, [labels[0]])) # 对lables进行闭合

# 3.绘制各簇对应的点线图
# y轴的设置:0 1 2 3
for i in range(len(nums_min_max)):
    temp_list = nums_min_max[i]  # 获得对应簇数值特征数据
    temp = np.concatenate((temp_list, [temp_list[0]]))  # 完成闭合
    ax.plot(angles, temp, 'o-', color=colors[i], label=i)

# 4.添加说明标签、显示雷达图
ax.set_thetagrids(angles * 180 / np.pi, labels)  # 设置极坐标
ax.set_rlim(-0.2, 1.2)  # 设置半径刻度
plt.title("数值特征对比分析")  # 设置标题
plt.legend()  # 类说明标签
plt.show()

原始数据集如下链接:
https://download.csdn.net/download/weixin_47686861/44751106

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐