岳松同学

2020-09-28   阅读量: 949

运用K-Means聚类分析广告效果

扫码加入数据分析学习群

一、

什么是用户行为分析:

用户行为分析:

在获得网站访问量最基本数据的情况下,

对有关数据进行统计、分析,

从中

发现用户访问网站的规律,

并将这些规律与网络营销策略相结合,

从而发现目前网络营销活

动中可能存在的问题,并为进一步的修正或者是重新制定网络营销策略提供依据。

以上只是很多种情况中一种———

-

针对网站的用户行为分析。那么,对于目前的互联网行

业成千上万的产品,我们又该如何重新定义用户行为分析呢?重新定义的用户行为是什么

呢?

1

分析用户行为,那我们应该先确定用户群体特征;

2

用户对产品的使用率。

网站类产品

主要体现在

点击率、点击量、访问量、访问率、

访问模块、页面留存时间

等等;

移动应用产品

主要体现在

下载量、使用频率、使用模块

等;

3

用户使用产品的时间。比如用户基本是每天中的什么时候使用产品。

综合以上说说的几点,其实用户行为分析可以这样来看:

用户行为分析就是对用户使用产

品过程中的所有数据(包括下载量、使用频率、访问量、访问率、留存时间等等)进行收

集、整理、统计、分析用户使用产品的规律,为产品的后续发展、优化或者营销等活动提

供有力的数据支撑。

二、

用户行为分析方式都有哪些?

既然是对用户的行为进行分析,

那么在得到数据后,

我们需要

如何进行行为分析

呢?分析方

式有哪些呢?这里我们主要从几个维度来分析:

方式、

侧重、

优缺点。

应该具体从何开始呢?

我们先说说用户行为分析的方式:

1

网站数据分析。通过对

每个模块

的点击率、点击量、访问量进行数据捕获,然后进行

分析;

2

用户基本动作分析。用户访问留存时间、访问量等;

3

关联调查数据分析。主要在电商上的相关推荐、你可能喜欢等等;

4

用户属性和习惯分析。

对用户属性和用户习惯两个维度进行分析。

用户属性包括性别、

年龄等固有的;用户习惯包括用户的一起喜爱度、流量习惯、访问习惯等等;

5

用户活跃度分析。

综合以上可以概括为:

以数据分析为导向、

以产品设计反馈为导向、

以对用户的调查为导向。

通过上面的分析方式,

我们需要整理出每种方式的分析侧重点。

那么,

下面我们谈谈用户行

为分析的侧重点,主要有以下几点:

1

网站数据分析的侧重点:数据监测、挖掘、收集、整理、统计。

2

用户基本动作分析侧重点:统计用户基本信息,比如:性别、年龄、地域,分析用户

群体;

3

关联分析侧重点:分析数据为精准营销提供数据支撑;

4

用户活跃度侧重点:

主要是用户的使用频率进行分析,

可以得出分析为什么用户喜欢

使用这个产品这个功能。

三、

用户行为分析的工具有哪些?如何做好用户行为分析?

工欲善其事必先利其器,

我们知道了我们需要做什么事情,

那么我们应该用什么工具来提高

效率呢?

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

本案例,通过各类广告渠道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'
'390
270'
13、广告卖点:打折、满减、满赠、秒杀、直降、满返

导入库,加载数据

In [3]:

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模块%matplotlib inline## 设置属性防止中文乱码mpl.rcParams['font.sans-serif'] = [u'SimHei']mpl.rcParams['axes.unicode_minus'] = False

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

In [4]:

raw_data = pd.read_table(r'E:\py练习\数据分析\广告投放\ad_performance.txt',delimiter='\t')raw_data.head()

Out[4]:


渠道代号日均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满减

In [5]:

raw_data.to_csv(r'E:\py练习\数据分析\广告投放\ad_performance.csv')

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

数据审查

In [6]:

# 查看基本状态raw_data.head(2)  # 打印输出前2条数据

Out[6]:


渠道代号日均UV平均注册率平均搜索量访问深度平均停留时间订单转化率投放总时间素材类型广告类型合作方式广告尺寸广告卖点
0A2033.690.00710.02142.3071419.770.025820jpgbannerroi140*40打折
1A387178.700.00400.03242.0489157.940.003019jpgbannercpc140*40满减

In [7]:

raw_data.info()# 打印数据类型分布
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 889 entries, 0 to 888
Data columns (total 13 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   渠道代号    889 non-null    object 
 1   日均UV    889 non-null    float64
 2   平均注册率   889 non-null    float64
 3   平均搜索量   889 non-null    float64
 4   访问深度    889 non-null    float64
 5   平均停留时间  887 non-null    float64
 6   订单转化率   889 non-null    float64
 7   投放总时间   889 non-null    int64  
 8   素材类型    889 non-null    object 
 9   广告类型    889 non-null    object 
 10  合作方式    889 non-null    object 
 11  广告尺寸    889 non-null    object 
 12  广告卖点    889 non-null    object 
dtypes: float64(6), int64(1), object(6)
memory usage: 90.4+ KB

In [9]:

raw_data.describe().round(2).T # 打印原始数据基本描述性信息

Out[9]:


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

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

查看缺失值情况:

In [10]:

# 缺失值审查na_cols = raw_data.isnull().any(axis=0)  # 查看每一列是否具有缺失值na_cols

Out[10]:

渠道代号      False
日均UV      False
平均注册率     False
平均搜索量     False
访问深度      False
平均停留时间     True
订单转化率     False
投放总时间     False
素材类型      False
广告类型      False
合作方式      False
广告尺寸      False
广告卖点      False
dtype: bool

In [11]:

raw_data.isnull().sum().sort_values(ascending=False)# 查看具有缺失值的行总记录数

Out[11]:

平均停留时间    2
广告卖点      0
广告尺寸      0
合作方式      0
广告类型      0
素材类型      0
投放总时间     0
订单转化率     0
访问深度      0
平均搜索量     0
平均注册率     0
日均UV      0
渠道代号      0
dtype: int64

变量之间的相关性分析:

In [12]:

# 相关性分析raw_data.corr().round(2).T # 打印原始数据相关性信息

Out[12]:


日均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

In [13]:

# 相关性可视化展示import seaborn as sns corr = raw_data.corr().round(2)sns.heatmap(corr,cmap='Reds',annot = True)
E:\Anaconda3\lib\importlib\_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject
  return f(*args, **kwds)

Out[13]:

<matplotlib.axes._subplots.AxesSubplot at 0x2a8e9ed08c8>

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

数据处理

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

In [14]:

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

类别变量的独热编码:

In [ ]:

 

In [16]:

# 类别变量取值cols=["素材类型","广告类型","合作方式","广告尺寸","广告卖点"]for x in cols:
    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']
-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·
变量【广告卖点】的取值有:
['打折' '满减' '满赠' '秒杀' '直降' '满返']
-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·

In [17]:

# 字符串分类独热编码处理cols = ['素材类型','广告类型','合作方式','广告尺寸','广告卖点'] model_ohe = OneHotEncoder(sparse=False)  # 建立OneHotEncode对象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.]]

In [18]:

# 用pandas的方法ohe_matrix1=pd.get_dummies(raw_data2[cols])ohe_matrix1.head(5)

Out[18]:


素材类型_gif素材类型_jpg素材类型_sp素材类型_swf广告类型_banner广告类型_tips广告类型_不确定广告类型_暂停广告类型_横幅合作方式_cpc...广告尺寸_480*360广告尺寸_600*90广告尺寸_900*120广告尺寸_960*126广告卖点_打折广告卖点_满减广告卖点_满赠广告卖点_满返广告卖点_直降广告卖点_秒杀
00100100000...0000100000
10100100001...0000010000
20100100001...0000010000
30100100001...0000010000
40100100001...0000010000

5 rows × 27 columns

数据标准化:

In [19]:

# 数据标准化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.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]]

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

In [20]:

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

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

建立模型

In [21]:

# 通过平均轮廓系数检验得到最佳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('{:*^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.45757883]
 [4.         0.50209812]
 [5.         0.4800359 ]
 [6.         0.47761127]
 [7.         0.48330881]]
最优的K值是:4 
对应的轮廓系数是:0.5020981194788054

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

聚类结果特征分析与展示

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

In [22]:

# 将原始数据与聚类标签整合cluster_labels = pd.DataFrame(cluster_labels_k, columns=['clusters'])  # 获得训练集下的标签信息merge_data = pd.concat((raw_data2, cluster_labels), axis=1)  # 将原始处理过的数据跟聚类标签整合merge_data.head()

Out[22]:


渠道代号日均UV平均注册率平均搜索量访问深度订单转化率投放总时间素材类型广告类型合作方式广告尺寸广告卖点clusters
0A2033.690.00710.02142.30710.025820jpgbannerroi140*40打折2
1A387178.700.00400.03242.04890.003019jpgbannercpc140*40满减2
2A38891.770.00220.05301.87710.00264jpgbannercpc140*40满减2
3A3891.090.00740.33824.24260.015310jpgbannercpc140*40满减2
4A3903.370.00280.17402.19340.000730jpgbannercpc140*40满减2

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

In [23]:

# 计算每个聚类类别下的样本量和样本占比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)
clusters    0    1    2   3
counts    349  313  154  73
##############################
clusters       0     1     2     3
percentage  0.39  0.35  0.17  0.08

每个类别内部最显著的特征:

In [24]:

# 计算各个聚类类别内部最显著特征值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  # 将列表转化为矩阵print('{:*^60}'.format('每个类别主要的特征:'))all_cluster_set = pd.concat((clustering_count, clustering_ratio, cluster_pd),axis=0)  # 将每个聚类类别的所有信息合并all_cluster_set
*************************每个类别主要的特征:*************************

Out[24]:


0123
counts34931315473
percentage0.390.350.170.08
日均UV933.0151390.012717.421904.37
平均注册率0.0030.0030.0050.003
平均搜索量0.0640.1520.0510.106
访问深度5.9161.1680.9470.943
订单转化率0.0060.0170.0070.009
投放总时间8.778.1998.5298.217
素材类型jpgswfjpgswf
广告类型横幅不确定bannertips
合作方式cpcroicpccpm
广告尺寸600*90600*90308*388450*300
广告卖点直降打折满减打折

图形化输出:

In [28]:

#各类别数据预处理num_sets = cluster_pd.iloc[:6, :].T.astype(np.float64)  # 获取要展示的数据num_sets_max_min = model_scaler.fit_transform(num_sets)  # 获得标准化后的数据print(num_sets)print('-'*20)print(num_sets_max_min)
       日均UV  平均注册率  平均搜索量   访问深度  订单转化率  投放总时间
0   933.015  0.003  0.064  5.916  0.006  8.770
1  1390.013  0.003  0.152  1.168  0.017  8.199
2  2717.419  0.005  0.051  0.947  0.007  8.529
3  1904.371  0.003  0.106  0.943  0.009  8.217
--------------------
[[0.00000000e+00 0.00000000e+00 1.28712871e-01 1.00000000e+00
  0.00000000e+00 1.00000000e+00]
 [2.56106801e-01 0.00000000e+00 1.00000000e+00 4.52443193e-02
  1.00000000e+00 0.00000000e+00]
 [1.00000000e+00 1.00000000e+00 0.00000000e+00 8.04343455e-04
  9.09090909e-02 5.77933450e-01]
 [5.44358789e-01 0.00000000e+00 5.44554455e-01 0.00000000e+00
  2.72727273e-01 3.15236427e-02]]

In [29]:

# 画图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]]))  # 建立相同首尾字段以便于闭合# 画雷达图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="第%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="upper right" ,bbox_to_anchor=(1.2,1.0))  # 设置图例位置

Out[29]:

<matplotlib.legend.Legend at 0x2a8ea250708>

数据结论

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

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

类别1(索引为2类的渠道)
这类广告媒体除了访问深度和投放时间较高,其他属性较低,因此这类广告媒体效果质量较差,并且占到39%,因此这类是主题渠道之一。
业务部门要考虑他的实际投放价值。

类别2(索引为1类的渠道)
这类广告媒体除了访问深度略差,在平均搜索量、日均UV、订单转化率等广告效果指标上表现良好,是一类综合效果较好的渠道。
但是日均UV是短板,较低。无法给企业带来大量的流量以及新用户,这类广告的特质适合用户转化,尤其是有关订单的转化提升。

类别3(索引为0类的渠道)
这类广告媒体的显著特征是日均UV和注册率较高,其“引流”和“拉新”效果好,可以在广告媒体中定位为引流角色。
符合“广而告之”的诉求,适合“拉新”使用。

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


42.9768 2 0 关注作者 收藏

评论(0)


暂无数据

推荐课程