失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 【Python数据挖掘实战案例】K-Means广告效果聚类分析

【Python数据挖掘实战案例】K-Means广告效果聚类分析

时间:2020-06-04 00:46:37

相关推荐

【Python数据挖掘实战案例】K-Means广告效果聚类分析

作者:杨啊小强

来源:Python数据科学修炼之路

本案例的业务场景:

假如你们公司投放广告的渠道很多,每个渠道的客户性质也可能不同,比如在优酷视频投广告和今日头条投放广告,效果可能会有差异。现在需要对广告效果分析实现有针对性的广告效果测量和优化工作。

本案例,通过各类广告渠道90天内额日均UV,平均注册率、平均搜索率、访问深度、平均停留时长、订单转化率、投放时间、素材类型、广告类型、合作方式、广告尺寸和广告卖点等特征,将渠道分类,找出每类渠道的重点特征,为加下来的业务讨论和数据分析提供支持。

目 录

1、应用技术介绍

2、数据介绍

3、导入库,加载数据

4、数据审查

5、数据处理

6、建立模型

7、聚类结果特征分析与展示

8、数据结论

01

应用技术介绍

Law

01、数据预处理

a、数据标准化

数据无量纲化,去除数据的单位限制,将其转化为无量纲的纯数值,便于不同单位或者量级的指标能够进行和加权.比如身高与体重,房子数量与收入等。

b、独热编码OneHotEncoder

对于字符串类别类型的变量,不能直接带入模型,需要转化为数值型。

02、K-Means聚类算法

聚类算法:属于无监督机器学习算法,通过计算样本项之间的相似度(也称为样本间的距离),按照数据内部存在的数据特征将数据集划分为多个不同的类别,使类别内的数据比较相似,类别之间的数据相似度比较小。

闵可夫斯基距离(Minkowski):

当p为1的时候是曼哈顿距离(Manhattan)

当p为2的时候是欧式距离(Euclidean)

当p为无穷大的时候是切比雪夫距离(Chebyshev)

算法思想(步骤):

a、选择初始化的k个类别中心a1,a2,...ak;

b、计算每个样本Xi到类别中心aj的距离,设定最近的类别j

c、将每个类别的中心点aj,替换为隶属该类别的所有样本的均值,作为新的质心。

d、重复上面两步操作,直到达到某个中止条件

中止条件为:组内最小平方误差MSE最小,或者达到迭代次数,或者簇中心点不再变化。

之前文章有介绍(点击下方链接查看):

Python数据挖掘实战:客户价值识别实现差异化管理

聚类评估——轮廓系数

如何基于最优的数据尺度确定K-Means算法中的K值?

轮廓系数的思想:

最佳的聚类类别划分从数据特征上看,类内距离最小化且类别间距离最大化,直观的理解就是“物以类聚”:同类的“聚集”“抱团”,不同类的离得远。轮廓系数通过枚举每个K计算平均轮廓系数得到最佳值。

a(i) :i向量到同一簇内其他点不相似程度的平均值

b(i) :i向量到其他簇的平均不相似程度的最小值

轮廓系数的值是介于 [-1,1] ,越趋近于1代表内聚度和分离度都相对较优。

将所有点的轮廓系数求平均,就是该聚类结果总的轮廓系数。

02

数据介绍

Law

01 数据维度概况

除了渠道唯一标识,共12个维度,889行,有缺失值,有异常值。

02数据13个维度介绍

1、渠道代号:渠道唯一标识

2、日均UV:每天的独立访问量

3、平均注册率=日均注册用户数/平均每日访问量

4、平均搜索量:每个访问的搜索量

5、访问深度:总页面浏览量/平均每天的访问量

6、平均停留时长=总停留时长/平均每天的访问量

7、订单转化率=总订单数量/平均每天的访客量

8、投放时间:每个广告在外投放的天数

9、素材类型:'jpg' 'swf' 'gif' 'sp'

10、广告类型:banner、tips、不确定、横幅、暂停

11、合作方式:'roi' 'cpc' 'cpm' 'cpd'

12、广告尺寸:'140*40' '308*388' '450*300' '600*90' '480*360' '960*126' '900*120'

'390*270'

13、广告卖点:打折、满减、满赠、秒杀、直降、满返

03

导入库,加载数据

Law

importpandasaspdimportnumpyasnpimportmatplotlibasmplimportmatplotlib.pyplotaspltfromsklearn.preprocessingimportMinMaxScaler,OneHotEncoderfromsklearn.metricsimportsilhouette_score#导入轮廓系数指标fromsklearn.clusterimportKMeans#KMeans模块%matplotlibinline##设置属性防止中文乱码mpl.rcParams['font.sans-serif']=[u'SimHei']mpl.rcParams['axes.unicode_minus']=False

以上是加载库的国际惯例,OneHotEncoder是独热编码,如果一个类别特征有n个类别,将该变量按照类别分裂成N维新变量,包含则标记为1,否则为0,用N维特征表示原来的特征。

读取数据:

raw_data=pd.read_table('ad_performance.txt',delimiter='\t')raw_data.head()渠道代号日均UV平均注册率平均搜索量访问深度平均停留时间订单转化率投放总时间素材类型广告类型合作方式广告尺寸广告卖点0A2033.690.00710.02142.3071419.770.025820jpgbannerroi140*40打折1A387178.700.00400.03242.0489157.940.003019jpgbannercpc140*40满减2A38891.770.00220.05301.8771357.930.00264jpgbannercpc140*40满减3A3891.090.00740.33824.2426364.070.015310jpgbannercpc140*40满减4A3903.370.00280.17402.1934313.340.000730jpgbannercpc140*40满减

渠道代号是唯一标识,日均UV到投放总时间是数值型(float和int)变量,后面是字符型变量。

04

数据审查

Law

#查看基本状态print('{:*^60}'.format('数据前两行:'))print(raw_data.head(2))#打印输出前2条数据print('{:*^60}'.format('数据类型:'))print(pd.DataFrame(raw_data.dtypes).T)#打印数据类型分布print('{:*^60}'.format('数据统计描述:'))print(raw_data.describe().round(2).T)#打印原始数据基本描述性信息***************************数据前两行:***************************渠道代号日均UV平均注册率平均搜索量访问深度平均停留时间订单转化率投放总时间素材类型广告类型\0A2033.690.00710.02142.3071419.770.025820jpgbanner1A387178.700.00400.03242.0489157.940.003019jpgbanner合作方式广告尺寸广告卖点0roi140*40打折1cpc140*40满减***************************数据类型:****************************渠道代号日均UV平均注册率平均搜索量访问深度平均停留时间订单转化率投放总时间\0objectfloat64float64float64float64float64float64int64素材类型广告类型合作方式广告尺寸广告卖点0objectobjectobjectobjectobject**************************数据统计描述:***************************countmeanstdmin25%50%75%max日均UV889.0540.851634.410.066.18114.18466.8725294.77平均注册率889.00.000.000.000.000.000.000.04平均搜索量889.00.030.110.000.000.000.011.04访问深度889.02.173.801.001.391.792.2298.98平均停留时间887.0262.67224.361.64126.02236.55357.984450.83订单转化率889.00.000.010.000.000.000.000.22投放总时间889.016.058.511.009.0016.0024.0030.00

上面代码,分别展示前两条数据、所有特征的数据类型、以及数值型特征的五值分布

查看缺失值情况:

#缺失值审查na_cols=raw_data.isnull().any(axis=0)#查看每一列是否具有缺失值print('{:*^60}'.format('含有缺失值的列:'))print(na_cols[na_cols==True])#查看具有缺失值的列print('总共有多少数据缺失:{0}'.format(raw_data.isnull().any(axis=1).sum()))#查看具有缺失值的行总记录数**************************含有缺失值的列:**************************平均停留时间Truedtype:bool总共有多少数据缺失:2# 也可以用下面的代码查看raw_data.isnull().sum().sort_values(ascending=False)

变量之间的相关性分析:

#相关性分析print('{:*^60}'.format('Correlationanalysis:'))print(raw_data.corr().round(2).T)#打印原始数据相关性信息*******************Correlationanalysis:********************日均UV平均注册率平均搜索量访问深度平均停留时间订单转化率投放总时间日均UV1.00-0.05-0.07-0.020.04-0.05-0.04平均注册率-0.051.000.240.110.220.32-0.01平均搜索量-0.070.241.000.060.170.13-0.03访问深度-0.020.110.061.000.720.160.06平均停留时间0.040.220.170.721.000.250.05订单转化率-0.050.320.130.160.251.00-0.00投放总时间-0.04-0.01-0.030.060.05-0.001.00

前面有有写过,皮尔逊相关的文章,可以用热力图形象展示(放个链接方便回看):

Python数据分析综合小练习:销售数据分析

#相关性可视化展示importseabornassnscorr=raw_data.corr().round(2)sns.heatmap(corr,cmap="Reds",annot=True)

可以看到,“访问深度”和“平均停留时间”相关性比较高,相关性高说明两个变量在建立模型的时候,作用是一样或者效果是一样的,可以考虑组合或者删除其一。

05

数据处理

Law

数据了解的差不多了,我们开始时处理数据,把常规数据通过清洗、转换、规约、聚合、抽样等方式变成机器学习可以识别或者提升准确度的数据。

#1删除平均平均停留时间列raw_data2=raw_data.drop(['平均停留时间'],axis=1)

类别变量的独热编码:

#类别变量取值cols=["素材类型","广告类型","合作方式","广告尺寸","广告卖点"]forxincols:data=raw_data2[x].unique()print("变量【{0}】的取值有:\n{1}".format(x,data))print("-·"*20)变量【素材类型】的取值有:['jpg''swf''gif''sp']-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·变量【广告类型】的取值有:['banner''tips''不确定''横幅''暂停']-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·变量【合作方式】的取值有:['roi''cpc''cpm''cpd']-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·变量【广告尺寸】的取值有:['140*40''308*388''450*300''600*90''480*360''960*126''900*120''390*270']-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·变量【广告卖点】的取值有:['打折''满减''满赠''秒杀''直降''满返']-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·

#字符串分类独热编码处理cols=['素材类型','广告类型','合作方式','广告尺寸','广告卖点']model_ohe=OneHotEncoder(sparse=False)#建立OneHotEncode对象ohe_matrix=model_ohe.fit_transform(raw_data2[cols])#直接转换print(ohe_matrix[:2])out:[[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.]]#用pandas的方法ohe_matrix1=pd.get_dummies(raw_data2[cols])ohe_matrix1.head(5)

结果如下:

数据标准化:

数据标准化的意义开篇技术介绍有聊过,统一量纲。

#数据标准化sacle_matrix=raw_data2.iloc[:,1:7]#获得要转换的矩阵model_scaler=MinMaxScaler()#建立MinMaxScaler模型对象data_scaled=model_scaler.fit_transform(sacle_matrix)#MinMaxScaler标准化处理print(data_scaled.round(2))[[0.0.180.020.010.120.66][0.010.10.030.010.010.62][0.0.060.050.010.010.1]...[0.010.010.0.0.0.72][0.050.0.0.0.0.31][0.0.0.0.530.0.62]]

数据处理完,我们将独热编码的数据和标准化转化后的数据合并:

#合并所有维度X=np.hstack((data_scaled,ohe_matrix))

数据处理完,就可以带入模型进行训练了。

06

建立模型

Law

#通过平均轮廓系数检验得到最佳KMeans聚类模型score_list=list()#用来存储每个K下模型的平局轮廓系数silhouette_int=-1#初始化的平均轮廓系数阀值forn_clustersinrange(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下的平均轮廓系数ifsilhouette_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('{:*^60}'.format('K值对应的轮廓系数:'))print(np.array(score_list))#打印输出所有K下的详细得分print('最优的K值是:{0}\n对应的轮廓系数是:{1}'.format(best_k,silhouette_int))*************************K值对应的轮廓系数:*************************[[2.0.38655493][3.0.45864451][4.0.50209812][5.0.4800359][6.0.47761127][7.0.4935842]]最优的K值是:4对应的轮廓系数是:0.5020981194788053

轮廓系数确定最佳的K值,确定数据分为几类较为合理,开篇技术介绍有轮廓系数的介绍了,聚类效果的评价,之前文章有介绍过聚类数和簇内均方误差绘图出现拐点的时候可以确定为几类。

总体思想(评价指标)还是怎么聚才能使得簇内距离足够小,簇与簇之间平均距离足够大来评判。

当然,有兴趣的同学,可以查资料总结一下聚类的评价指标,怎么确定K值,K-Means有什么优缺点,怎么提升?··· ···

后续文章也可能会专门出个这方面的专题。

07

聚类结果特征分析与展示

Law

通过上面模型,我们其实给每个观测(样本)打了个标签clusters,即他属于4类中的哪一类:

#将原始数据与聚类标签整合cluster_labels=pd.DataFrame(cluster_labels_k,columns=['clusters'])#获得训练集下的标签信息merge_data=pd.concat((raw_data2,cluster_labels),axis=1)#将原始处理过的数据跟聚类标签整合merge_data.head()渠道代号日均UV平均注册率平均搜索量访问深度订单转化率投放总时间素材类型广告类型合作方式广告尺寸广告卖点clusters0A2033.690.00710.02142.30710.025820jpgbannerroi140*40打折01A387178.700.00400.03242.04890.003019jpgbannercpc140*40满减02A38891.770.00220.05301.87710.00264jpgbannercpc140*40满减03A3891.090.00740.33824.24260.015310jpgbannercpc140*40满减04A3903.370.00280.17402.19340.000730jpgbannercpc140*40满减0

然后看看,每个类别下的样本数量和占比情况:

#计算每个聚类类别下的样本量和样本占比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)clusters0123counts15431334973##############################clusters0123percentage0.170.350.390.08

接下来,我们看看每个类别内部最显著的特征:

#计算各个聚类类别内部最显著特征值cluster_features=[]#空列表,用于存储最终合并后的所有特征信息forlineinrange(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#将列表转化为矩阵print('{:*^60}'.format('每个类别主要的特征:'))all_cluster_set=pd.concat((clustering_count,clustering_ratio,cluster_pd),axis=0)#将每个聚类类别的所有信息合并all_cluster_set*******************每个类别主要的特征:*****************0 1 2 3counts 154313 349 73percentage0.170.350.390.08日均UV 2717.421390.01933.0151904.37平均注册率0.0050.0030.0030.003平均搜索量0.0510.1520.0640.106访问深度 0.9471.1685.9160.943订单转化率0.0070.0170.0060.009投放总时间8.5298.1998.778.217素材类型 jpgswf jpg swf广告类型 banner不确定 横幅 tips合作方式 cpcroi cpc cpm广告尺寸308*388 600*90600*90450*300广告卖点 满减打折 直降 打折

上面看着挺累的,不直观,我们图形化输出:

#各类别数据预处理num_sets=cluster_pd.iloc[:6,:].T.astype(np.float64)#获取要展示的数据num_sets_max_min=model_scaler.fit_transform(num_sets)#获得标准化后的数据

#画图fig=plt.figure(figsize=(6,6))#建立画布ax=fig.add_subplot(111,polar=True)#增加子网格,注意polar参数labels=np.array(merge_data1.index)#设置要展示的数据标签cor_list=['g','r','y','b']#定义不同类别的颜色angles=np.linspace(0,2*np.pi,len(labels),endpoint=False)#计算各个区间的角度angles=np.concatenate((angles,[angles[0]]))#建立相同首尾字段以便于闭合#画雷达图foriinrange(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="第%d类渠道"%(i))#画线ax.fill(angles,data,alpha=2.5)#设置图像显示格式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="upperright",bbox_to_anchor=(1.2,1.0))#设置图例位置

08

数据结论

Law

从案例结果来看,所有的渠道被分为4各类别,每个类别的样本量分别为:154、313、349 、73,对应占比分别为:17%、35%、39%、8%。

通过雷达图可以清楚的知道:

类别1(索引为2类的渠道)

这类广告媒体除了访问深度和投放时间较高,其他属性较低,因此这类广告媒体效果质量较差,并且占到39%,因此这类是主题渠道之一。

业务部门要考虑他的实际投放价值。

类别2(索引为1类的渠道)

这类广告媒体除了访问深度略差,在平均搜索量、日均UV、订单转化率等广告效果指标上表现良好,是一类综合效果较好的渠道。

但是日均UV是短板,较低。无法给企业带来大量的流量以及新用户,这类广告的特质适合用户转化,尤其是有关订单的转化提升。

类别3(索引为0类的渠道)

这类广告媒体的显著特征是日均UV和注册率较高,其“引流”和“拉新”效果好,可以在广告媒体中定位为引流角色。

符合“广而告之”的诉求,适合“拉新”使用。

类别4(索引为3类的渠道)

这类渠道各方面特征都不明显,各个流量质量和流量数量的指标均处于“中等”层次。不突出但是均衡,考虑在各场景下可以考虑在这个渠道投放广告。

基础知识 温故知新...

数据获取:关注后,后台回复“广告效果分析”获取,动手练练吧!

◆◆◆ ◆◆

长按二维码关注我们

数据森麟公众号的交流群已经建立,许多小伙伴已经加入其中,感谢大家的支持。大家可以在群里交流关于数据分析&数据挖掘的相关内容,还没有加入的小伙伴可以扫描下方管理员二维码,进群前一定要关注公众号奥,关注后让管理员帮忙拉进群,期待大家的加入。

管理员二维码:

猜你喜欢

●笑死人不偿命的知乎沙雕问题排行榜

●用Python扒出B站那些“惊为天人”的阿婆主!

●全球股市跳水大战,谁最坑爹!

●华农兄弟、徐大Sao&李子柒?谁才是B站美食区的最强王者?

●你相信逛B站也能学编程吗

如果觉得《【Python数据挖掘实战案例】K-Means广告效果聚类分析》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。