广告营销用户点击预测分析

零、数据集以及数据集简介以及任务分析

项目任务:

根据海量广告投放的用户点击数据,通过机器学习构建预测模型预估用户的是否进行广告点击,即给定某条广告相关的媒体、上下文内容等信息和用户标签的条件下,预测这个用户是否点击此广告。我们的任务就是通过分析数据,对于数据进行

训练数据集
train1.txt和train2.txt
两个数据集可以使用pandas读入

字段说明
instance_id样本id
click是否点击
adid广告id
advert_id广告主id
orderid订单id
advert_industry_inner广告主行业
advert_name广告主名称
campaign_id活动id
creative_id创意id
creative_type创意类型
creative_tp_dnf样式定向id
creative_has_deeplink响应素材是否有deeplink(Boolean)
creative_is_jump是否是落页跳转(Boolean)
creative_is_download是否是落页下载(Boolean)
creative_is_js是否是js素材(Boolean)
creative_is_voicead是否是语音广告(Boolean)
creative_width创意宽
creative_height创意高
app_cate_idapp分类
f_channel一级频道
app_id媒体id
inner_slot_id媒体广告位
app_paidapp是否付费
user_tags用户标签信息,以逗号分隔
city城市
carrier运营商
time时间戳
province省份
nnt联网类型
devtype设备类型
os_name操作系统名称
osv操作系统版本
os操作系统
make品牌(例如:apple)
model机型(例如:“iphone”)

一、数据预处理

1、加载检查数据

data = pd.read_csv("train1.txt",sep='\t')
data.append(pd.read_csv("train2.txt",sep='\t'))

在这里插入图片描述

(1)特殊特征

我们可以看到user_tags这个特征和其他的有很大的区别,他包含了多个特征,并且每个数据所含的user_tags的特征并不相同,所以为了方便后期处理我们先把user_tags特征从data中分离出来单独处理

user_tags = data["user_tags"]
data = data.drop("user_tags", axis=1)

(2)特殊特征的处理

由于user_tags特征较为特殊,并且长度不唯一,所以我们采用以下方式对他进行处理

1.补全空数据,这里默认为空的数据即为没有任何标签,在这里我们规定设为标签‘0’
2.统计每种用户标签在用户中出现的次数
3.取前save_n个在用户中出现的最多作为保留标签
4.假设数据条数为n,建立一个形状为(n,save_n)的二维零矩阵:user_tags_mark
5.如果第i条数据的用户标签中存在保留标签j,我们将user_tags_mark的第i行第j列置为1
6.为了方便之后对新数据进行预测,我们将标签对应的出现次数:tags_dict以及user_tags和user_tags_mark的映射关系tags_map一并保存下来
def get_tags(user_tags, save_n):
    user_tags.fillna('0', inplace=True)
    tags_dict = dict()
    for i in range(len(user_tags)):
        tl = user_tags[i].split(',')
        for t in tl:
            if t in tags_dict.keys():
                tags_dict[t] += 1
            else:
                tags_dict[t] = 1

    tags_dict = sorted(tags_dict.items(), key=lambda x:x[1], reverse=True)[:save_n]
    tags_dict = {key:value for key, value in tags_dict}
    tags_map = {key:value for value, key in enumerate(tags_dict.keys())}

    user_tags_mark = np.zeros((len(user_tags), len(tags_map)))
    for i in range(len(user_tags)):
        tl = user_tags[i].split(',')
        for t in tl:
            if t in tags_map.keys():
                user_tags_mark[i][tags_map[t]] += 1
    return user_tags, tags_dict, tags_map, user_tags_mark
            
user_tags, tags_dict, tags_map, user_tags_mark = get_tags(user_tags, 20)

(3)特殊特征处理后生成的新特征

在这里插入图片描述

2、数据类型与缺失值处理

(1)查看数据信息

data.info()

在这里插入图片描述

可以看到其中的make, model, osv, os_name, advert_industry_inner, f_channel, inner_slot_id, advert_name,app_cate_id, app_id都有缺失。但他们的补全方式不相同,其中make~advert_name的类型是object,观测数据后发现均是以字符串形式存储的数据、相关信息的缺失可以认为是由于技术手段或者用户不愿意透露导致的,所以这一部分信息的缺失本身也传达着一种信息,所以我们这里将这一类型的数据缺失标记为“NaN”,意为找不到其他数据信息。而app_cate_id, app_id数据类型为float,这里使用中位数来补全以反映大多数的情况。

注:此时的数据已经将user_tags分离出去了

(2)数据补全以及类型转换

由于计算机不能够对字符串格式的数据进行运算,所以我们要将字符串转换为计算机能够理解的标签,我们在数据补全的同时使用OrdinalEncoder将objects_list中的特征转换为标签的格式,并且将字符串和标签的对应关系保存下来(objects_cates)

objects_list = ["make", "model", "osv", "os_name", "advert_industry_inner", "f_channel", "inner_slot_id", "advert_name"]
floats_list = ["app_cate_id", "app_id"]


def Completer(data, bool_list=[], objects_list=[], floats_list=[]):
    from sklearn.preprocessing import OrdinalEncoder
    objects_cates = dict()
    flag = False
    for obj in objects_list:
        flag = True
        data[obj].fillna("NaN", inplace=True)
        
        data_cat = data[[obj]]
        encoder = OrdinalEncoder()
        data_cat = encoder.fit_transform(data_cat)
        cate_dict = dict()
        categories = encoder.categories_[0]
        for i in range(len(categories)):
            cate_dict[categories[i]] = i
        objects_cates[obj] = cate_dict
        data[obj]=data_cat.reshape(-1, 1)[:,0]

    for f in floats_list:
        median = data[f].median()
        data[f].fillna(median, inplace=True)
        
    return data, objects_cates, flag


data, objects_cates, flag = Completer(data, bool_list, objects_list, floats_list)

(3)补全后的数据

在这里插入图片描述

3、异常值分析

运用EllipticEnvelope和KNNImputer识别异常值并进行修改

bool_list = ["creative_is_jump", "creative_is_download", "creative_is_js", "creative_is_voicead", "creative_has_deeplink", "app_paid"]

def OutlierHander(data, boll_list):
    from sklearn.covariance import EllipticEnvelope
    from sklearn.impute import KNNImputer
    import numpy as np
    
    for b in bool_list:
        data[b] = data[b].astype(np.float64)
    detector = EllipticEnvelope() # 构造异常值识别器
    detector.fit(data) # 拟合识别器
    idx = detector.predict(data) == -1# 预测异常值
    ls = [i for i in range(len(data))]
    
    data[idx] *= np.nan
    imputer = KNNImputer()
    data = imputer.fit_transform(data)   
    return data

data = OutlierHander(data, bool_list)

注:1.这个函数的运行过程会非常慢;2.要将所有的bool类型转换之后才能进行补全

二、 探索性分析与特征工程

众所周知,用户标签(user_tags)可以表明一个一个用户的偏好,从而一定程度上反映用户是否会对广告进行点击。但是这个标签是多维度的数据,尤其是在我们利用用户标签生成新的特征(user_tags_mark)之后,只取一部分用户标签信息来进行分析很明显会引导我们进入一个误区,所以我们在这里保留用户标签这个特征不做分析

1、单变量图分析

(1)原数据变量分析

data.hist(bins=51, figsize=(20, 15))
plt.show()

在这里插入图片描述
从图中可以看到:
1.样本id(instance_id)分布比较均匀,并且按照生活常识来讲他对是否点击广告没有什么影响,所以可以去掉这一特征
2.数据的分布的时间(time)呈周期性,说明收集到的数据跟时间相关,在不同时间段中能收集到的数据不同表明不同时间用户看到广告的次数不同,所以我们需要添加新特征,如:周、月特征
3.省份、城市、媒体id、广告id、广告主id、订单id、活动id、创意id、样式定向id由于编码问题会影响作图效果以及后续的训练效果,所以在这里我们做了一个数据映射
4.点击和不点击的数据正负样本不均衡,在训练前应该进行欠采样,即减少对负样本的采样

(2)处理数据

1.添加新特征
data["time"] = pd.to_datetime(df['time'],unit='s',origin=pd.Timestamp('1970-01-01'))
data["month"] = data["time"].dt.month
data["dayofweek"] = data["time"].dt.dayofweek
2.id映射
city_dict =