用户广告点击情况预测

一、分析背景

电商平台的发展取决于用户。电商平台如何让用户点击里面的内容,就是留住用户的第一步。电商平台的首页往往会分成好几个模块,比如促销活动广告,而这些模块都是代表了部分商品。如果平台的活动广告不是用户喜欢的,那么这个活动就没有意义。准确判断用户是不是喜欢广告中的商品,可以大大改善广告点击情况。

二、分析目的

现有阿里云天池(https://tianchi.aliyun.com/dataset/dataDetail?dataId=56)提供的淘宝用户的广告点击数据。数据中包含了四张表,分别为用户行为日志behavior_log(简称为bl)、原始样本骨架raw_sample(简称为rs)、广告基本信息表ad_feature(简称为af)、用户基本信息表user_profile(简称为up),具体字段说明如表1:

表1

我们利用现有数据,使用用户画像分析和随机森林,来查看用户的广告点击偏好和预测raw_sample表中用户是否点击广告。

三、分析方法

1. 用户画像分析

针对用户的特征,分析什么种类的用户喜欢什么类型的广告。

2. 随机森林预测

使用数据挖掘方法,将数据分为训练集和测试集,通过训练分类预测模型来预测用户是否点击广告。

四、数据准备——数据清洗

1. user_profile表

查看表结构:

up = pd.read_csv(r'E:\datafile\ad_clik\user_profile.csv',index_col='userid')

up.info() 

up.describe()

发现无重复值、异常值和格式错误值,但cms_segid、cms_group_id、pvalue_level和new_user_class_level有缺失值。

对于缺失值处理:① 删除 ②增补

此次,我们删除了特征缺失很多的501条数据;对于仅城市层级缺失的数据,用随机森林方法进行增补;其他缺失情况的数据,按照全非空数据的比例进行增补。

2. ad_feature表

查看表结构,发现brand字段有缺失。通过adgroup_id字段连接raw_sample表,增补对应的brand。但是发现同一个adgroup_id有两个brand的情况,直接删除。

3. raw_sample表

无缺失值、重复值、异常值和格式错误值。

五、数据分析

1. up表中用户特征的分布情况

1.1 性别、是否大学生

以性别为例:

gender = up['final_gender_code'].value_counts()

# print(gender)

# 女性用户有684026人,男性用户有377241人

plt.figure()

plt.grid(alpha=0.4)

gender.plot(kind='bar')

plt.title('up表的性别分布情况',fontproperties=my_font)

plt.xlabel('性别(1为男,2为女)',fontproperties=my_font)

plt.ylabel('人数',fontproperties=my_font)

plt.show()

性别分布情况

结论:女性淘宝用户占比很大,淘宝用户主力是非大学生。

1.2 年龄层

年龄层分布情况

结论:年龄层分布基本符合高斯分布。年龄层为3的用户最多,最少的为6。我们可以推测出年龄层为3的是在30岁左右的青年。

1.3 消费档次

中档消费用户最多,其次为低档,高档的最少。

1.4 购物深度

淘宝深度用户占绝大多数,说明淘宝的用户忠诚度方面做得很好,与现实相符。

1.5 城市层级

城市层级为2的用户最多,最少的是层级为1的。可以推测,层级为2的城市是二线城市。而一线城市为何是最少的?一个解释就是一线城市数本身就比其他线城市少。

2. af表的广告属性分布情况

2.1 价格

首先我们将价格按照等距离分桶,查看分桶后的分布情况。

p = af['price']

bins = np.arange(0,600,10)

bins = pd.cut(p,bins)

bins = p.groupby(bins).count()

plt.figure(figsize=(30,8))

bins.plot(kind='bar')

plt.show()

我们可以发现,0-10、90-100、190-200、290-300、390-400、490-500是比周围价格区间的广告单元的数量都高。因为广告商品的价格都很喜欢198,99,98等类型的价格。至于价格在0-10的广告数量很多,是因为淘宝中此类商品本身就特别多。

2.2 商品类目

我们查看商品类目出现的个数:

cate = af['cate_id'].value_counts()

bins = np.arange(0,200,10)

bins = pd.cut(cate,bins)

bin_counts = cate.groupby(bins).count()

plt.figure(figsize=(8,8))

bin_counts.plot(kind='pie')

plt.show()

#结果表明:在这个时间段,打广告的商品类目大都比较零散,只有10个以内的广告单元的cate_id占了将近一半。

2.3 广告计划

在这个时间段内,大多数广告计划各不相同。

2.4 广告主

各个广告对应的广告主也各不相同。

2.5 广告所属品牌

广告所属品牌也很多,这也说明了淘宝中的商家并不存在垄断情况,市场还是良好的。

3. 用户的广告点击偏好

3.1 不同用户特征的商品类目偏好

在这里,我们根据点击量情况,查看不同类用户最经常点击的广告商品类目。

df_clk = df[df['clk']==1]

u = ['final_gender_code','age_level','pvalue_level','shopping_level','occupation','new_user_class_level ']

c = [[1,2],[1,2,3,4,5,6],[1,2,3],[1,2,3],[0,1],[1,2,3,4]]

m = 0

for i in u:

    cate_clk = df_clk.groupby([i,'cate_id']).count()['clk'].reset_index()

    s = c[m]

    m += 1

    for n in s:

        print(cate_clk[cate_clk[i]==n].sort_values(by='clk',ascending=False).head(1))

print('ok')

我们发现,无论是哪种类型的用户,点击量最高的广告商品类目都是6261。这需要区分清楚6261类广告是真的受用户偏爱,还是它只是曝光量很高但点击率不高。

我们先查看每个商品类目的点击量和点击率情况:

cate_y = df['cate_id'][df['clk']==1].value_counts().reset_index()

cate_y.columns = ['cate_id','clk']

# cate_n = df['cate_id'][df['clk']==0].value_counts().reset_index()

# cate_n.columns = ['cate_id','nclk']

cate_sum = df['cate_id'].value_counts().reset_index()

cate_sum.columns = ['cate_id','counts']

cate = pd.merge(cate_y,cate_sum,how='outer',on='cate_id')

cate = cate.fillna(0)

cate['clk_ratio'] = cate['clk']/cate['counts']

cate['clk_ratio'] = cate['clk_ratio'].map(lambda x:('%.4f')%x)

cate['clk_ratio'] = cate['clk_ratio'].astype(float)

cate.describe([0.1,0.3,0.5,0.7,0.8,0.9,0.95])

从点击率的分布情况,可以看出平均点击率为0.0476,大多数商品类目的点击率都不是很高。

cate[cate['cate_id']==6261]

查看6261的点击率为0.0605,在分位点70%以上,这类商品不仅点击量高而且点击率也高,说明它们的广告还是很吸引用户的。

再进一步,在最偏好的商品类目中,查看最喜欢的品牌:

u = ['final_gender_code','age_level','pvalue_level','shopping_level','occupation','new_user_class_level ']

c = [[1,2],[1,2,3,4,5,6],[1,2,3],[1,2,3],[0,1],[1,2,3,4]]

m = 0

for i in u:

    cate_clk = df_clk[df_clk['cate_id']==6261].groupby([i,'brand']).count()['clk'].reset_index()

    s = c[m]

    m += 1

    for n in s:

        print(cate_clk[cate_clk[i]==n].sort_values(by='clk',ascending=False).head(1))

print('ok')

结果如下:

总体来看,品牌为234846、商品类目为6261的广告最常被用户点击。只有年龄层为1和2,以及大学生用户最喜欢的品牌是82527。

同样重复上面步骤,查看点击率情况:

品牌为234846的广告点击率
品牌为82527的广告点击率

按品牌划分的广告点击率平均为0.0412;品牌为234846的广告点击率为0.0608,在分位点75%左右;品牌为82527的点击率为0.0685,超过分为点80%。说明在商品类目为6261中,绝大多数用户最常点击品牌为234846的广告;而对于低年龄层的用户和大学生用户来说,最喜欢品牌为82527的广告,可以推测这个品牌很受年轻人喜爱。

3.2 不同用户特征的价格偏好

u = ['final_gender_code','age_level','pvalue_level','shopping_level','occupation','new_user_class_level ']

c = [[1,2],[1,2,3,4,5,6],[1,2,3],[1,2,3],[0,1],[1,2,3,4]]

m = 0

for i in u:

    cate_clk = df_clk.groupby([i,'price']).count()['clk'].reset_index()

    s = c[m]

    m += 1

    for n in s:

        print(cate_clk[cate_clk[i]==n].sort_values(by='clk',ascending=False).head(1))       

print('ok')

结果如下:

点击的广告价格分布情况:

结果表明:淘宝用户经常点击价格为198的广告。而低年龄层用户消费能力低一些,最喜欢点击98、99左右价格的广告。结合价格分布情况,侧面验证了大多数淘宝用户的消费层次是中档的。

3.3 不同用户特征的广告活动计划偏好

与上面代码类目,得到以下结果:

其中,活动计划为118601的广告最吸引用户,尤其是女性用户和深度用户。

4. 用户的广告点击情况预测

由于数据量太大,我们只选取三天的数据,进行预测。

4.1 数据转换

由于广告属性的cate_id、campaign_id、customer和brand无法直接进行建模,需要进行数据转换。此处,按照广告属性的点击量和点击率情况,将它们进行等频分桶,分成十个等级,转换成8个新变量。

以cate_id为例:

# 先计算cate_id的点击量和点击率

cate_y = df['cate_id'][df['clk']==1].value_counts().reset_index()

cate_y.columns = ['cate_id','clk']

# cate_n = df['cate_id'][df['clk']==0].value_counts().reset_index()

# cate_n.columns = ['cate_id','nclk']

cate_sum = df['cate_id'].value_counts().reset_index()

cate_sum.columns = ['cate_id','counts']

cate = pd.merge(cate_y,cate_sum,how='outer',on='cate_id')

cate = cate.fillna(0)

cate['clk_ratio'] = cate['clk']/cate['counts']

cate['clk_ratio'] = cate['clk_ratio'].map(lambda x:('%.4f')%x)

cate['clk_ratio'] = cate['clk_ratio'].astype(float)

# 点击量分桶

cate['cate_clk_bins'] = pd.qcut(cate['clk'],13,duplicates='drop',labels=[1,2,3,4,5,6,7,8,9,10])

cate['cate_clk_bins'] = cate['cate_clk_bins'].astype(int)

# cate['clk_bins'].unique().size

## 点击率分桶

cate['cate_clk_ratio_bins'] = pd.qcut(cate['clk_ratio'],13,duplicates='drop',labels=[1,2,3,4,5,6,7,8,9,10])

cate['cate_clk_ratio_bins'] = cate['cate_clk_ratio_bins'].astype(int)

# cate['clk_ratio_bins'].unique().size

cate.drop(['clk','counts','clk_ratio'],axis=1,inplace=True)

4.2 相关分析和特征筛选

对于定类数据之间的相关分析,我们使用卡方检验;对于定类和定距数据,我们使用eta系数。

from sklearn.feature_selection import chi2,SelectKBest

train_x = df_012.drop('clk',axis=1).values

train_y = df_012['clk'].tolist()

selector = SelectKBest(chi2,k='all')

selector.fit(train_x, train_y)

scores = selector.scores_

print(scores) 

pvalues = selector.pvalues_

print(pvalues)  #p值都小于0.05

selector = SelectKBest(chi2,k=10)

v = selector.fit(train_x, train_y).get_support(indices=True)

print(v)

scores = selector.scores_

print(scores) 

根据特征得分,只保留10个定类特征,删除了'pid','clk','age_level','pvalue_level','shopping_level','occupation','new_user_class_level ','cate_clk_bins'这些特征。

同时使用SPSS计算了eta系数,结果显示它们相关。

4.2 训练数据并预测

选择使用随机森林模型,进行用户广告点击情况预测。

首先将三天的数据切分成训练集和测试集:

from sklearn.ensemble import RandomForestClassifier

from sklearn.model_selection import cross_val_score,train_test_split

todrop = ['pid','clk','age_level','pvalue_level','shopping_level','occupation','new_user_class_level ','cate_clk_bins']

x = df_012.drop(todrop,axis=1).values

y = df_012['clk'].tolist()

train_X,test_X, train_y, test_y = train_test_split(x,y,test_size=1/5)

然后对训练集进行交叉验证训练模型:

clf1 = RandomForestClassifier(n_estimators=10,max_depth=None,min_samples_split=2,random_state=0)

scores = cross_val_score(clf1,train_X,train_y,scoring='accuracy',cv=5)

clf1.fit(train_X,train_y)

print(scores.mean())

print(scores.std()) 

以精确率为得分,训练结果平均得分为0.9401836626955434,标准差为0.00010639743381447468。

模型训练结束之后,使用预测集预测:

y_pred = clf1.predict(test_X)

最后,做一个预测结果验证,计算准确率:

test = pd.DataFrame([y_pred,test_y],index=['y_pred','test_y'])

test = test.T

print('预测准确率:',test[(y_pred==test_y)]['y_pred'].size/test['y_pred'].size)  # 0.9404274614218243

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,784评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,745评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,702评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,229评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,245评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,376评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,798评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,471评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,655评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,485评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,535评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,235评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,793评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,863评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,096评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,654评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,233评论 2 341