精华内容
下载资源
问答
  • 谈到CTR,都多多少少有些了解,尤其在互联网广告这块,简而言之,就是给某个网络服务使用者推送一个广告,该广告点击的概率,这个问题难度简单到街边算命随口告诉你今天适不适合娶亲、适不适合搬迁一样,也可以...
  • 主要介绍了使用python进行广告点击率的预测的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 在线广告点击率预测研究;深度学习;机器学习;常见预测方法;
  • 大多数经典搜索引擎会根据其点击率(CTR)选择广告并对其进行排名。 为了预测广告点击率,经常需要考虑历史点击信息。 由于我们没有大量有关这些广告的历史数据,因此准确预测新广告点击率对于现实应用而言具有...
  • 广告点击率是互联网广告投放的重要依据,有效地预测广告的点击率,对于提高广告投放的效率有着至关重要的作用。在训练点击率预测模型的过程中,往往面临着广告及用户的数量巨大以及训练数据集稀疏的问题,从而导致...
  • kaggle广告点击率转化预测第二名代码
  • 点击率预测可以提高用户对所展示互联网广告的满意度,支持广告的有效投放,是针对用户进行广告的个性化推荐的重要依据.对于没有历史点击记录的用户,仍需对其推荐广告,预测所推荐广告点击率.针对这类用户,以贝叶斯网...
  • 这是2014年由CriteoLabs在kaggle上发起的广告点击率预估挑战项目。 使用TensorFlow1.0和Python 3.5开发
  • CTR广告点击率预估

    2020-04-20 13:08:24
    1、广告分类 在线OnLine广告分类可以分为以下几个大类: 展示类广告:腾讯的广点通 搜索广告:百度蜂巢 社交平台上广告:微博上广告 ... CPC(Cost per Click) 搜索广告中使用,按照点击收费----百度、Google的...

    1、广告分类

    在线OnLine广告分类可以分为以下几个大类:

    1. 展示类广告:腾讯的广点通
    2. 搜索广告:百度蜂巢
    3. 社交平台上广告:微博上广告

    2、广告计费方式

    1. CPM(cost per mile) 按照展示收费,不管用户看到广告没,只要广告每天达到一定的曝光次数,就需要给钱,广告组会给平台组出钱
    2. CPC(Cost per Click) 搜索广告中使用,按照点击收费----百度、Google的收费方式
    3. CPA(Cost Per Action) 必须用户点击了广告并下单之后才会收费的方式

    3、什么是CTR

    Click-Through-Rate (点击通过比率)简写为CTR(CTR=点击量/展示量,即 Click / Show content。)

    4、CTR计算公式

    CTR=Click(点击)/Impression(曝光) *100%
    CTR=点击量/浏览量
    
    CTR是衡量互联网广告效果的一项重要指标。

    5、统计指标

    展现量、点击量、点击率、访客数、访问次数、浏览量

    1、展现量

     展现量有助于您了解推广结果覆盖了多少网民,是一个数量上的概念。

    2、访客数(UV)

    访客数就是指一天之内到底有多少不同的用户访问了你的网站。访客数要比IP数更能真实准确地反映用户数量。百度统计完全抛弃了IP这个指标,而启用了访客数这一指标,是因为IP往往不能反映真实的用户数量。尤其对于一些流量较少的企业站来说,IP数和访客数会有一定的差别。

      访客数主要是以cookie为依据来进行判断的,而每台电脑的cookie也是不一样的。有些情况下IP数会大于真实的访客数。有时候访客数也会大于IP数。访客数要比IP数更能真实准确地反映用户数量。

    3、访问次数

    访问次数是指访客完整打开了网站页面进行访问的次数。访问次数是网站的访问速度的衡量标准。

    4、浏览量(PV)

    浏览量和访问次数是呼应的。用户访问网站时每打开一个页面,就记为1个PV。同一个页面被访问多次,浏览量也会累积。一个网站的浏览量越高,说明这个网站的知名度越高,内容越受用户喜欢。一味地重视PV也是没有太大意义的(PV跟点击量差不多吧)。

      PV是一个重要的指标,反映了网站内容是否对用户有足够的吸引力。对于竞价而言,只能是侧面反映,因为我们设置了访问URL。很多用户需求也非常明确,来到网站之后,往往只会寻找自己需求的产品,所以一味地重视PV也是没有太大意义的。应该把重点内容展示给目标客户就可以了,就没必要一味地追求PV值,追求那些转化率、跳出率、UV、转化次数等那才是重点。

    5、转化次数

     潜在用户在我们的网站上完成一次我们期望的行为,就叫做一次转化。我们可以在百度统计的后台设置相应的转化页面,用户访问这个页面1次,就记为1次转化。

    6、转化率

    转化率=转化次数/访问次数

    对竞价而言,是关键词和访问页面的精准的指标。转化率可以用来衡量网络营销的效果。如果我们在A、B两个网站同时投放了广告,A网站每天能带来100次用户访问,但是只有1个转化,B网站每天能带来10次用户访问,但是却有5个转化。这就说明B网站带来的转化率更高,用户更加精准,网络营销效果更好。

    7、平均访问时长

    平均访问时长是衡量网站用户体验的一个重要指标;平均访问时长是用户访问网站的平均停留时间。平均访问时长=总访问时长/访问次数。如果用户不喜欢网站的内容,可能稍微看一眼就关闭网页了,那么平均访问时长就很短;如果用户对网站的内容很感兴趣,一连看了很多内容,或者在网站停留了很长时间,平均访问时长就很长。

    8、平均访问页数

    平均访问页数也是衡量网站的用户体验的指标;平均访问页数是用户访问网站的平均浏览页数。平均访问页数=浏览量/访问次数。平均访问页数很少,说明访客进入你的网站后访问少数几个页面就离开了。

    9、跳出率

    跳出率是反映网站流量质量的重要指标;跳出率是指访客来到网站后,只访问了一个页面就离开网站的访问次数占总访问次数的百分比。跳出率=只访问一个页面就离开网站的访问次数/总访问次数,跳出率越低说明流量质量越好,用户对网站的内容越感兴趣。

     

     

    展开全文
  • 广告点击率预测问题初探

    千次阅读 2018-10-08 15:50:56
    广告点击率预测问题初探 国庆7天参加了一个广告点击率预测的小竞赛,作为只看过机器学习实战的小白,纯粹抱着学习的心态去开眼,果然被大神按在地上虐呢,不过也学到了很多知识。感谢很多大佬都开源并分享了他们的...

    广告点击率预测问题初探
    国庆7天参加了一个广告点击率预测的小竞赛,作为只看过机器学习实战的小白,纯粹抱着学习的心态去开眼,果然被大神按在地上虐呢,不过也学到了很多知识。感谢很多大佬都开源并分享了他们的竞赛经验,帮助我入了一点点门。下面的代码借鉴了几位大佬的分享,不妥删。
    一、数据处理
    数据有train.txt 训练集和test.txt测试集。每一行数据为一个样本,可分为5类数据,包含基础广告投放数据、广告素材信息、媒体信息、用户信息和上下文信息。训练集共1001650条数据,其中‘click’字段为要预测的标签,其它34个字段为特征字段。测试集共40024条数据,与训练集文件相比,测试集文件无‘click’字段,其它字段同训练集。
    之前我以为机器学习就是把构造好的数据集丢到模型里训练,通过调参提升效果;现在知道了这种业务问题需要对业务和数据有足够的理解,然后通过数据预处理、特征构造等方法使模型能发挥比较好的效果。这就是特征工程的工作。
    1、首先,我学到了使用pandas库在jupyter notebook上进行数据观察和初步处理,一些基本操作如下:

    # 载入数据
    import pandas as pd
    train = pd.read_csv('train.txt',sep='\t')
    test = pd.read_csv('test.txt',sep='\t')
    data = pd.concat([train,test],axis=0,ignore_index=True)
    
    # 观察全局数据
    data.head()	#查看数据开头5行
    data.columns	#数据列标题(特征名称)
    data.index	#数据行索引
    data.nunique()	#查看数据各特征的类别分布
    data.shape	#数据行、列数
    
    # 观察局部数据
    data['location'].unique()	#location的不同类别
    data['location'].value_counts()		#location不同类别的样本数
    data.groupby('location')['click'].agg({'mean','count'})	#location不同类别的个数及平均点击率
    data.groupby('location')['cityID'].agg('unique')	#location和cityID是否有交叉
    
    # 处理数据
    data=data.fillna(-1) #将空值设为-1
    data.sort_values('time')	#按时间排序
    data['click']=data['click'].apply(lambda x:int(x))	#对click列中每一个元素进行操作
    data.drop('cityID',axis=1,inplace=True)	#删除某列
    del data['cityID']	#同上
    data.to_csv('result.txt')	#将数据写入文件
    

    总结来说,这次对数据的处理有以下要点:
    (1)时间数据:一般数据集中给出的都是时间戳,要把它们转化为年月日时等,然后再观察时间的周期性特点(即不同时间的广告点击情况)。

    # 时间转化
    init_time = data['time'].min() 
    data['day'] = ((data['time'].values - init_time) / (3600 *24))/astype(int)
    data['hour'] =( (data['time'].values - init_time - data['day'].values * 3600 * 24) / 3600).astype(int)
    # 或者
    # data['day'] = data['time'].apply(lambda x: int(time.strftime("%d", time.localtime(x))))
    # data['hour'] = data['time'].apply(lambda x: int(time.strftime("%H", time.localtime(x))))
    
    # 随机挑选三天观察hour周期性
    data.loc[data['day'] == 0].groupby('hour')['click'].agg({'mean','count'})
    data.loc[data['day'] == 1].groupby('hour')['click'].agg({'mean','count'})
    data.loc[data['day'] == 2].groupby('hour')['click'].agg({'mean','count'})
    
    # 观察day周期性
    data.groupby('day')['click'].agg({'mean','count'})
    

    (2)只有一个类别的数据:舍弃,因为这些数据对结果不起什么作用。
    (3)nunique相同的数据:比较它们的交叉关系,若不存在交叉关系则只取其中一个(例如location和cityID,名称和编号等)。
    (4)类别数据:将包含样本数很少(例如少于20个)的类别合并为其他类(赋值为-1)。

    # 将各特征中属于样本数少于20的类别合并为其他类
    threshold = 20
    from collections import Counter
    for col in data.columns.values:
        print(col,'combining')
        if col in ["instance_id", "click", "user_tags","hour","day","time"]:
            continue
        col_counter = Counter(data[col])
        small_cate_list = list()
        for col, count in col_counter.items():
            if count > threshold:
                continue
            small_cate_list.append(col)
        for item in small_cate_list:
            data[col] = data[col].apply(lambda _item: -1 if _item == item else _item)
    print('少数类合并完毕.')
    

    (5)观察数据得到新特征:例如将广告宽度和广告长度相乘得到广告面积特征;发现广告ID前缀某几位的点击率相差很大,将它们提取为adid_prefix特征;将广告行业特征分割为主行业和二级行业。

    # 分割广告行业特征
    data['advert_industry_inner_1'] ,data['advert_industry_inner_2'] = data['advert_industry_inner'].apply(lambda x: x.split('_'))
    # 提取广告ID前3位
    data['ad_prefix']=data['adid'].apply(lambda x: int(str(x)[:3]))
    #计算广告面积
    data['area'] = data['creative_height'] * data['creative_width']
    

    (6)构造历史点击率特征:

    import gc
    for feat in rate_features:
        # 垃圾回收
        gc.collect()
        res = data['instance_id']
        temp = data[[feat,'period','click']]
    
        # 得到样本各特征的历史点击率,第一天为当天值,其他为当天之前的值的和
        for period in range(1,8):
            if period == 1:
                # 该feat各值出现在数据中的次数
                count=temp.groupby([feat]).apply(lambda x: x['click'][(x['period']<=period).values].count()).reset_index(name=feat+'_all')
                # 该feat各值被点击的次数
                count1=temp.groupby([feat]).apply(lambda x: x['click'][(x['period']<=period).values].sum()).reset_index(name=feat+'_1')
            else:
                count=temp.groupby([feat]).apply(lambda x: x['click'][(x['period']<period).values].count()).reset_index(name=feat+'_all')
                count1=temp.groupby([feat]).apply(lambda x: x['click'][(x['period']<period).values].sum()).reset_index(name=feat+'_1')
    
            # 将上面的count和count1拼在一起,并填补缺失值
            count[feat+'_1']=count1[feat+'_1']
            count.fillna(value=0, inplace=True)
    
            # 计算点击率
            count[feat+'_rate'] = pd.Series([round(x,5) for x in count[feat + '_1'] / count[feat + '_all']])
            count['period']=period
    
            # 只保留点击率这一列
            count.drop([feat+'_all', feat+'_1'],axis=1,inplace=True)
            count.fillna(value=0, inplace=True)
            res=res.append(count,ignore_index=True)
        print(feat,' over')
    res.to_csv('history_click.csv',index=False)
    

    (7)一个小tips:在数据处理过程中,可以保存一些比较费时的操作的中间结果,这样下次需要用的时候可以直接调用。
    (8)构造贝叶斯平滑后的转化率(CTR):转化率就是广告的点击次数/曝光次数,即r=C/I. 为了避免特殊情况的影响(例如只曝光1次就被点击了1次的转化率是100%,远高于曝光100次中点击50次的情况,但参考意义有限),利用先验知识设置一个初值,将原转化率结合初值形成新的转化率,因为初值较大,所以能降低特殊情况的影响,这就用到了贝叶斯平滑。
    CTR平滑作了两个假设:
    假设一,所有的广告有一个自身的ctr,这些ctr服从一个Beta分布。
    假设二,对于某一广告,给定展示次数时和它自身的ctr,它的点击次数服从一个伯努利分布 Binomial(I, ctr)。
    根据假设构造公式之后,按照优化求解方法得到参数α和β,新的转化率就修正成了:r=(C + α) / (I + α+ β).
    但是用这个方法存在一定的风险,这有点像用了结果来训练模型(类似于用答案来解题),我试的时候就出现了线下结果特别好,一上线成绩就很差的情况。

    class BayesianSmoothing(object):
        def __init__(self, alpha, beta):
            self.alpha = alpha
            self.beta = beta
    
        def update(self, imps, clks, iter_num, epsilon):
            for i in range(iter_num):
                new_alpha, new_beta = self.__fixed_point_iteration(imps, clks, self.alpha, self.beta)
                if abs(new_alpha - self.alpha) < epsilon and abs(new_beta - self.beta) < epsilon:
                    break
                # print(new_alpha, new_beta, i)
                self.alpha = new_alpha
                self.beta = new_beta
    
        def __fixed_point_iteration(self, imps, clks, alpha, beta):
            numerator_alpha = 0.0
            numerator_beta = 0.0
            denominator = 0.0
            for i in range(len(imps)):
                numerator_alpha += (special.digamma(clks[i] + alpha) - special.digamma(alpha))
                numerator_beta += (special.digamma(imps[i] - clks[i] + beta) - special.digamma(beta))
                denominator += (special.digamma(imps[i] + alpha + beta) - special.digamma(alpha + beta))
    
            return alpha * (numerator_alpha / denominator), beta * (numerator_beta / denominator)
    
    
    def PH(feature,data):
        # -------------------------------------
        print('开始统计平滑')
        bs = BayesianSmoothing(1, 1)
        dic_i = dict(Counter(data[feature].values))
        dic_cov = dict(Counter(data[data['label'] == 1][feature].values))
        l = list(set(data[feature].values))
        I = []
        C = []
        for i in l:
            I.append(dic_i[i])
        for i in l:
            if i not in dic_cov:
                C.append(0)
            else:
                C.append(dic_cov[i])
        print('开始平滑操作')
        bs.update(I, C, 100000, 0.0000000001)
        print(bs.alpha, bs.beta)
        print('构建平滑转化率')
        dic_PH = {}
        for i in l:
            if i not in dic_i:
                dic_PH[i] = (bs.alpha) / (bs.alpha + bs.beta)
            elif i not in dic_cov:
                dic_PH[i] = (bs.alpha) / (dic_i[i] + bs.alpha + bs.beta)
            else:
                dic_PH[i] = (dic_cov[i] + bs.alpha) / (dic_i[i] + bs.alpha + bs.beta)
        df_ctr = pd.DataFrame({feature: list(dic_PH.keys()),
                            'PH_{}'.format(feature): list(dic_PH.values())})
        return df_ctr
    

    (9)多值属性:例如User_tags里面每一行都有多个值,可以把它们当作文本处理,使用CountVector或者TF-IDF等文本工具进行操作,之后使用SVD提取topN。由于这个过程非常耗内存,最好使用压缩矩阵存储,见下。

    2、上述几乎都对数据特征作了一些处理,下面我学到的方法是使用sklearn等库对数据进行编码、压缩存储和特征选择。
    (1)label编码
    简单粗暴地将数据集中复杂的编码变成有序的数列,可能会损失一些信息,一般在数据处理和特征构造之后进行。

    from sklearn.preprocessing import LabelEncoder
    enc = LabelEncoder()
    for feat in cate_features:
        enc.fit(data[feat])
        data[feat] = enc.transform(data[feat])
    

    (2)one_hot编码、压缩存储和CV操作
    由于one_hot编码是一个占内存的操作,可以使用压缩矩阵来存储,同理之前的多值操作也可以这么用压缩矩阵存储。

    from sklearn.feature_extraction.text import CountVectorizer
    from scipy import sparse
    from sklearn.preprocessing import OneHotEncoder
    
    csr = sparse.csr_matrix((data.shape[0], 0))
    
    # 对类别特征进行onehot编码
    enc = OneHotEncoder()
    for feat in cate_features:]:
           dat = data[feat].values.reshape(-1, 1)
            enc.fit(dat)
            csr = sparse.hstack((csr,enc.transform(dat)), 'csr','bool')
    
    # 对多值属性进行文本处理
    cv = CountVectorizer(min_df=20)
    dat = data['user_tags'].astype(str)
    cv.fit(dat)
    cv_csr = cv.transform(dat)
    csr = sparse.hstack((train_csr, cv_csr), 'csr', 'bool')
    
    # svd
    # 上面的方法是将user_tags的值转化为onehot编码后与类别特征一起存储到压缩矩阵中
    # 而下面则是将user_tags的值转化为onehot编码后的压缩矩阵,再进行奇异值分解SVD降为50维,以浮点数形式合并到原数据集中
    threshold = 50
    svd = TruncatedSVD(n_components=threshold)
    svd_data = svd.fit_transform(cv_csr)
    svd_columns = ["svd_{i}".format(i=i) for i in range(threshold)]
    svd_df = pd.DataFrame(data=svd_data, columns=svd_columns)
    data = pd.concat(data, svd_df)
    
    # 存储压缩矩阵 
    # 如果不进行svd,则矩阵中包含user_tags的onehot编码值
    # 如果进行了svd,则矩阵中只有类别特征的onehot编码值
    sparse.save_npz(path + '/onehot_csr.npz', csr)
    
    # 加载压缩矩阵
    csr = sparse.load_npz(path + '/onehot_csr.npz').tocsr().astype('bool')
    

    (3)特征选择

    from sklearn.feature_selection import SelectFromModel
    from sklearn.feature_selection import VarianceThreshold
    from sklearn.ensemble import ExtraTreesClassifier
    
    # 舍去方差低于某阈值的特征
    selector = VarianceThreshold(threshold=0.05).fit(data)
    selector_columns = data.columns[ selector.get_support(indices=True)]
    data = data[selecor_columns]
    
    # 从模型中选择特征
    clf = ExtraTreesClassifier().fit(data, labels)
    selector = SelectFromModel(clf, threshold="1.25*mean", prefit=True)
    selector_columns = data.columns[ selector.get_support(indices=True)]
    data = data[selecor_columns]
    

    二、建模
    1、单模型
    lightGBM是较常用的一个模型。它是基于树学习的梯度提升框架,支持高效率的并行训练,使用直方图算法,总之就是有很多优点的样子。原理我也不是很了解,具体可看这个博客https://blog.csdn.net/u012513618/article/details/78441676
    以及官方文档http://lightgbm.apachecn.org/cn/latest/Features.html
    在这里用法如下:

    from sklearn.model_selection import StratifiedKFold
    import lightgbm as lgb
    import datetime
    
    # 构建分类器
    params={
    	boosting_type='gbdt', 	# 使用哪种算法,这里用传统梯度提升决策树
    	num_leaves=32,	# 一棵树上的叶子数
    	reg_alpha=0, 	# L1正则
    	reg_lambda=0.1,	# L2正则
        max_depth=-1, 	# 限制树的最大深度,这里是不限制
        n_estimators=2018, 	# 迭代次数
        objective='binary',		# 分类目标,这里是二分类
        subsample=0.8, 	# 不进行重采样的情况下随机选择部分(80%)数据,加速训练
        colsample_bytree=0.8,	#  每棵树训练之前随机选择数据,类似上一个
        subsample_freq=1,	# bagging的频率,1意味着每1次迭代执行bagging
        learning_rate=0.03, 	# 学习率
        random_state=2000,	# ?
        n_jobs=-1	# ?
    }
    clf = lgb.LGBMClassifier(**params)
    
    # 五折交叉检验
    n_folds=5
    prediction = predict[['instance_id']]
    prediction['predicted_score'] = 0
    
    skf = StratifiedKFold(n_splits=n_folds, shuffle=True, random_state=2018)
    for ind, (train_ind, test_ind) in enumerate(skf.split(train_x, train_y)):
    	print(ind,'folding...')
        lgb_model.fit(train_x[train_ind], train_y[train_ind],
                     	 eval_names=['train','valid'],
                     	 eval_metric='logloss',
                     	 eval_set=[(train_x[train_ind], train_y[train_ind]),
                         (train_x[test_ind], train_y[test_ind])], 
                         early_stopping_rounds=100)
        test_pred = lgb_model.predict_proba(predict_x,num_iteration=lgb_model.best_iteration_)[:, 1]
        print('test mean:', test_pred.mean())
        prediction['predicted_score'] = prediction['predicted_score'] + test_pred
        
    prediction['predicted_score'] = prediction['predicted_score'] / 5
    mean = prediction['predicted_score'].mean()
    print('mean:', mean)
    
    # 将结果写入文件
    now = datetime.datetime.now().strftime('%m-%d-%H-%M')
    prediction.to_csv(path + "/result_sub/lgb_baseline_%s.csv" % now, index=False)
    

    2、还有一个方法是使用多个模型并进行融合,可以把几个模型的预测结果当作特征,也可以按权重合并结果。但是这个方法我用得不是很好,线上结果很差,可能是没有进行合适的操作。代码写法和上面单模型类似。
    另外,我也稍微看了下腾讯广告算法的代码,其中一些方法我还没有进行尝试,包括:
    (1)某一个模型使用前两天的数据为训练集,最后一天为测试集,与其他模型融合。
    (2)构造用户点击(或不点击)广告之前的特征,例如安装app数量、最近安装的app、同类app等。

    展开全文
  • 广告点击率预估模型中,特征提取是关键因素,特征的好坏直接影响到最终模型的效果。针对如何提高广告点击率预估效率问题,在Hadoop大数据平台环境中,提出了基于梯度提升决策树(gradient boost decision tree,...
  • 基于用户画像的互联网广告点击率预测模型研究.pdf
  • 网络广告点击率影响因素分析对大学生的实证分析 论文关键词网络广告点击率广告诚信广告传播 论文摘要提取5个影响网络广告点击率的重要因素 _的大学生进行实证研究发现网络资源的丰富性和网络受众的习惯对网络广告的...
  • 广告点击率预测

    千次阅读 2020-05-25 17:37:46
    广告点击率预测项目,目的是通过广告和用户信息预测一个广告是否被点击。数据来自Kaggle竞赛(https://www.kaggle.com/c/avazu-ctr-prediction),源数据比较大,选取前40000条。 1. 数据读取和分析 import numpy...

    广告点击率预测项目,目的是通过广告和用户信息预测一个广告是否被点击。数据来自Kaggle竞赛(https://www.kaggle.com/c/avazu-ctr-prediction),源数据比较大,选取前400000条。

    1. 数据读取和分析

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    
    #数据读取
    data_df = pd.read_csv('train_subset.csv')
    
    #展示头部数据,分两次展示或者调整python设置达到一次展示所有特征的效果
    #data_df.iloc[:, :12].head()
    #data_df.iloc[:, 12:].head()
    pd.set_option('display.max_columns', None)
    data_df.head(20)

    大致推断一下一些关键特征的业务含义(源数据已经脱敏):

    特征名称

    业务含义推断
    id数据唯一的ID
    click是否点击广告
    hour数据收集时间(yymmddhh)
    banner_pos广告投放位置信息
    site_id广告客户网站(某个游戏网站 vs 商家网站)
    site_domain网站某种大类(游戏 vs 电商)
    site_category网站某种小类(手游 vs 零食)
    app_id广告提供商APP
    app_domainAPP大类(社交类 vs 内容类)
    app_categoryAPP类别(微博 vs 头条)
    device_id设备硬件地址(可能是电脑mac地址 vs 手机 IMEI,每个设备唯一)
    device_ip设备互联网地址(可能多个设备公用)
    device_model设备型号
    device_type设备类型(手机 vs 电脑)
    device_conn_type设备连接类型(Wifi vs 4G)

    C14

    -
    C15-
    C16-
    C17-
    C18-
    C19-
    C20-
    C21-

    对于前面四个特征 -  id、 click、hour、 banner_pos, 其中,每条数据id都不一样,是没有意义的,显然可以直接删除。

    click是标签,对标签分布的理解是必不可少的。

    pos_counts = data_df[data_df.click==1].count()['click']
    neg_counts = data_df[data_df.click==0].count()['click']
    
    
    print("positive rate: ", pos_counts/data_df.count()['click'])
    print("negtive rate: ", neg_counts/data_df.count()['click'])

    通过上述的数据,可以很容易看出被点击的次数要远小于没有被点击的次数,所以数据是不平衡的,但这个不平衡还没有严重到像1000:1那么夸张。

    由于样本的不平衡,使用准确率是不明智的,所以评估指标我们选用F1-score

    hour特征

    时间特征有可能对我们帮助,比如是否凌晨点击率要低于早上的,是否早上的要低于下午的?

    #先把hour的格式调整一下
    data_df['hour'] = pd.to_datetime(data_df['hour'],format = '%y%m%d%H',errors = 'raise')
    #打印一下hour特征
    data_df.hour.describe()

    其实从上述的结果中可以看到,时间的区间为10-21的00点到10-21的02点,也就是2个小时的间隔。所以在使用这个特征的时候,可以把小时的特征提取出来,因为日期都是一样的

    banner_pos特征

    这是广告投放的位置,从直观上来看对广告点击的结果影响比较大,所以做一下可视化的分析并更好地理解这个特征。

    groups_click = data_df[data_df.click==1].groupby('banner_pos').count()
    groups_no_click = data_df[data_df.click==0].groupby('banner_pos').count()
    plt.title('Visualization of Banner Position and Click Events')
    plt.bar(range(len(groups_no_click)),list(groups_no_click['click']),label = '0',width = 0.5)
    plt.bar(range(len(groups_click)),list(groups_click['click']),bottom = list(groups_no_click['click']), tick_label =list(groups_click.index), label = '1',width = 0.5)
    plt.legend(title = 'click')
    plt.xlabel('banner_pos')
    plt.xticks(rotation=90)
    plt.show()

    生成完上面的图之后能感觉到这个特征还是蛮重要的,而且由于banner_pos=2,4,5,7的样本比较少,在图里不那么直观。所以我们就尝试打印一下一个表格。

    #calculate total amount for a row
    row_total = data_df.groupby('banner_pos').count()['click']
    
    #calculate amount for zero & one
    zero_total = data_df[data_df.click==0].groupby('banner_pos').count()['click']
    one_total = data_df[data_df.click==1].groupby('banner_pos').count()['click']
    
    #calculate result
    zero_result = zero_total / row_total
    one_result = one_total / row_total
    
    #create DataFrame and add column values from above
    rate_df = pd.DataFrame(index = groups_click.index.values,columns=['0','1'])
    rate_df['0'] = list(zero_result)
    rate_df['1'] = list(one_result)
    rate_df.index.name = 'banner_pos'
    rate_df.columns.name = 'click'
    rate_df

    site特征

    site_features = ['site_id', 'site_domain', 'site_category']
    data_df[site_features].describe()

    app特征

    app_features = ['app_id', 'app_domain', 'app_category']
    data_df[app_features].describe()

    重点研究一下app_category特征是否跟标签有较强的关系,为了直观一些,画出app_category的直方图。

    category_click = data_df[data_df.click==0].groupby('app_category').count()['click']
    category_no_click = data_df[data_df.click==1].groupby('app_category').count()['click']
    category_total = data_df.groupby('app_category').count()['click']
    
    zero_result2 = category_click/category_total
    one_result2 = category_no_click/category_total
    
    plt.title('CTR for app_category feature')
    plt.bar(np.array(
        .index),zero_result2,label = '0',width = 0.5)
    plt.bar(np.array(category_click.index),one_result2,bottom = zero_result2, tick_label =np.array(category_click.index), label = '1',width = 0.5)
    plt.legend(title = 'click')
    plt.xlabel('app_category')
    plt.xticks(rotation=90)
    plt.show()

    device特征

    device_features = ['device_id', 'device_ip', 'device_model', 'device_type', 'device_conn_type']
    data_df[device_features].astype('object').describe()

    同样,画出device_conn_type的直方图(device_type类似)

    device_conn_type_click = data_df[data_df.click==0].groupby('device_conn_type').count()['click']
    device_conn_type_no_click = data_df[data_df.click==1].groupby('device_conn_type').count()['click']
    device_conn_type_total = data_df.groupby('device_conn_type').count()['click']
    
    zero_result3 = device_conn_type_click/device_conn_type_total
    one_result3 = device_conn_type_no_click/device_conn_type_total
    
    plt.title('CTR for device_conn_type feature')
    plt.bar(np.array(device_conn_type_click.index),zero_result3,label = '0',width = 0.5)
    plt.bar(np.array(device_conn_type_click.index),one_result3,bottom = zero_result3, tick_label =np.array(device_conn_type_click.index), label = '1',width = 0.5)
    plt.legend(title = 'click')
    plt.xlabel('device_conn_type')
    plt.xticks(rotation=90)
    plt.show()

    其他特征:C1, C14-C21

    c_features = ['C1', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21']
    data_df[c_features].astype('object').describe()

    拿C1为例,数据集里共有6个不同的类别,同样看一下C1和点击率的直方图。

    c1_click = data_df[data_df.click == 0].groupby('C1').count()['click']
    c1_no_click = data_df[data_df.click == 1].groupby('C1').count()['click']
    c1_total = data_df.groupby('C1').count()['click']
    
    one_result4 = c1_click / c1_total
    zero_result4 = c1_no_click / c1_total
    
    plt.bar(np.array(c1_click.index),zero_result4,label = '0',width = 0.5)
    plt.bar(np.array(c1_click.index),one_result4,bottom = zero_result4,label = '1',tick_label=np.array(c1_click.index),width = 0.5)
    plt.title('CTR for C1 feature')
    plt.xlabel('C1')
    plt.legend(title = 'click')
    plt.show()

    2. 特征构造

    这里的特征有必要构造的不多,hour是一个。可以根据上面显示的hour特征情况,将其变成离散变量:也就是2014-10-21 00点对应到0, 2014-10-21 01点对应到1, 2014-10-21 02点对应到2。

    data_df['hour'] = data_df['hour'].dt.hour

    3. 特征转化

    将类别型特征独热编码,并删除原始特征。为此,需要先删除稀疏特征。

    data_df.drop('device_id', axis=1, inplace=True)
    data_df.drop('device_ip', axis=1, inplace=True)
    data_df.drop('site_id', axis=1, inplace=True)
    data_df.drop('app_id', axis=1, inplace=True)
    
    one_hot_columns = data_df.columns.values.tolist()
    
    one_hot_columns.remove('click')
    
    data_df=pd.get_dummies(data_df,columns = one_hot_columns)

    构建训练数据和测试数据

    feature_names = np.array(data_df.columns[data_df.columns != 'click'].tolist())
    
    from sklearn.model_selection import train_test_split
    
    X_train, X_test, y_train, y_test = train_test_split(
        data_df[feature_names].values, 
        data_df['click'].values,
        test_size=0.2,
        random_state=42
    )
    
    print (X_train.shape, X_test.shape, y_train.shape, y_test.shape)
    
    (319999, 1076) (80000, 1076) (319999,) (80000,)
    

    4. 特征选择

    独热编码之后,特征一下子变得非常多,需要做一下特征选择,这里使用了逻辑回归+L1正则。

    from sklearn.linear_model import LogisticRegression
    from sklearn.feature_selection import SelectFromModel
    from sklearn.metrics import f1_score
    from sklearn.model_selection import KFold, cross_val_score
    import warnings
    
    params_c = np.logspace(-4, 1, 11)
    
    warnings.filterwarnings('ignore')
    
    cv_score=[]
    for c in params_c:
        lr_clf = LogisticRegression(penalty='l1', C=c)
        scores = cross_val_score(lr_clf,X_train,y_train,cv=10,scoring='f1')
        cv_score.append(scores.mean())
    
    c_best = params_c[cv_score.index(max(cv_score))]

    通过最优超参c_best,重新训练训练集数据,并选出特征。

    # 通过c_best值,重新在整个X_train里做训练,并选出特征。
    lr_clf = LogisticRegression(penalty='l1', C=c_best)
    lr_clf.fit(X_train, y_train) # 在整个训练数据重新训练
    
    select_model = SelectFromModel(lr_clf, prefit=True)
    selected_features = select_model.get_support()  # 被选出来的特征

    重新构造训练数据和测试数据。

    # 重新构造feature_names
    feature_names = feature_names[selected_features]
    
    # 重新构造训练数据和测试数据
    X_train = X_train[:, selected_features]
    X_test = X_test[:, selected_features]

    5. 模型训练与评估

    这里使用决策树算法做分类。

    from sklearn.tree import DecisionTreeClassifier
    
    params_min_samples_split = np.linspace(5, 20, 4)
    params_min_samples_leaf = np.linspace(2, 10, 5)
    params_max_depth = np.linspace(4, 10, 4)
    
    #构造决策树并做交叉验证。
    model = GridSearchCV(estimator =DecisionTreeClassifier(),param_grid={'max_depth':params_max_depth},cv=10)
    model.fit(X_train,y_train)
    
    #在测试数据上预测,打印在测试集上的结果
    predictions = model.predict(X_test)
    print(classification_report(y_test, predictions))

     

    说明一下,因为这里只选取了源数据的前400000条,一些关键特征作用被弱化了。像hour特征或许跟标签有很大关系,但是选取的数据里只有三个值,训练过程发现不了这层关系,导致最终的预测结果不太理想。

    展开全文
  • 淘宝展示广告点击率分析

    千次阅读 2020-05-07 16:43:22
    Ali_Display_Ad_Click是阿里巴巴提供的一个淘宝展示广告点击率数据集。 三、数据简介 1.原始样本骨架raw_sample: 从淘宝网站中随机抽样了114万用户8天内的广告展示/点击日志(2600万条记录),构成原始的样本骨架。...

    一、 项目背景

    大数据时代的背景下,广告投放成为了互联网各个行业中运营推广的主流。对于电商行业来说,广告投放的效果,取决于广告投放后为平台带来了多少转化。要有转化,首先就要有流量(点击),因此,如何对广告进行精准投放,提高广告的点击率,进而实现精准营销就显得尤为重要。
    下面我们以阿里巴巴提供的淘宝展示广告点击率数据集为例进行分析。

    二、数据来源

    https://tianchi.aliyun.com/dataset/dataDetail?dataId=56.
    Ali_Display_Ad_Click是阿里巴巴提供的一个淘宝展示广告点击率数据集。

    三、数据简介

    1.原始样本骨架raw_sample:
    从淘宝网站中随机抽样了114万用户8天内的广告展示/点击日志(2600万条记录),构成原始的样本骨架。
    字段说明如下:

    字段说明
    user_id脱敏过的用户ID
    adgroup_id脱敏过的广告单元ID
    time_stamp时间戳
    pid资源位
    noclk为1代表没有点击;为0代表点击
    clk为0代表没有点击;为1代表点击

    由于数据量较大,本文中只截取其中前200W条数据进行分析。
    2.用户基本信息表user_profile:
    本数据集涵盖了raw_sample中全部用户的基本信息。字段说明如下:

    字段说明
    user_id脱敏过的用户ID
    cms_segid微群ID
    cms_group_idcms_group_id
    final_gender_code性别 1:男,2:女
    age_level年龄层次
    pvalue_level消费档次,1:低档,2:中档,3:高档
    shopping_level购物深度,1:浅度,2:中度,3:深度
    occupation是否大学生 ,1:是,0:否
    new_user_class_level城市层级

    3.广告基本信息表ad_feature:
    本数据集涵盖了raw_sample中全部广告的基本信息。字段说明如下:

    字段说明
    adgroup_id脱敏过的广告ID
    cate_id脱敏过的商品类目ID
    campaign_id脱敏过的广告计划ID
    customer_id脱敏过的广告主ID
    brand脱敏过的品牌ID
    price宝贝的价格

    其中一个广告ID对应一个商品(宝贝),一个宝贝属于一个类目,一个宝贝属于一个品牌。

    四、数据预处理

    4.1 数据导入

    1. 导入类库

    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    %matplotlib inline
    import seaborn as sns
    sns.set_style('darkgrid')         # 设置网格类型,默认
    
    # 用来正常显示中文标签
    plt.rcParams['font.sans-serif'] = ['SimHei']
    # 用来正常显示负号
    plt.rcParams['axes.unicode_minus'] = False
    

    2. 导入数据集

    # 用户基本信息表
    user_data = pd.read_csv('D:/淘宝展示广告点击率预估数据集/user_profile.csv')  # 读取数据
    print(user_data.shape)         # (1061768, 9):说明该表中一共有1061768行、9列
    user_data.head()  # 输出数据前5行
    
    # 广告基本信息表
    ads = pd.read_csv('D:/淘宝展示广告点击率预估数据集/ad_feature.csv')
    print(ads.shape)       # (846811, 6):说明该表中一共有846811行、6列
    ads.head()
    
    # 从原始样本骨架数据raw_sample中选取200W数据作为样本数据
    raw_sample = pd.read_csv('D:/淘宝展示广告点击率预估数据集/raw_sample.csv',nrows=2000000)
    # 将截取的前200W行数写入sample_data.csv文件中
    raw_sample.to_csv('D:/淘宝展示广告点击率预估数据集/sample_data.csv',index=False,sep=',')
    dataset = pd.read_csv('D:/淘宝展示广告点击率预估数据集/sample_data.csv')  # 读取数据
    print(dataset.shape)  # (2000000, 6):说明该表中一共有2000000行、6列
    dataset.head()
    

    从上到下依次为用户基本信息表user_data、广告基本信息表ads、样本数据表dataset,如下图所示:
    在这里插入图片描述在这里插入图片描述在这里插入图片描述

    4.2 缺失值处理

    1. 缺失值检测

    # 获取用户基本信息表user_data每列的缺失值占比
    user_data_null = user_data.isnull().sum()/len(user_data)*100
    user_data_null = user_data_null.drop(user_data_null[user_data_null==0].index).sort_values(ascending=False)     # 将缺失值占比从高到低排序
    missing_data = pd.DataFrame({'Missing Ratio(%)':user_data_null})
    print(f'user_data含有缺失值的属性个数:{len(user_data_null)}')
    print(missing_data)
    print('-' * 60)
    
    # 获取广告基本信息表ads每列的缺失值占比
    ads_null = ads.isnull().sum()/len(ads)*100
    ads_null = ads_null.drop(ads_null[ads_null==0].index).sort_values(ascending=False)     # 将缺失值占比从高到低排序
    missing_data = pd.DataFrame({'Missing Ratio(%)':ads_null})
    print(f'ads含有缺失值的属性个数:{len(ads_null)}')
    print(missing_data)
    print('-' * 60)
    
    # 获取样本数据表dataset每列的缺失值占比
    dataset_null = dataset.isnull().sum()/len(dataset)*100
    dataset_null = dataset_null.drop(dataset_null[dataset_null==0].index).sort_values(ascending=False)     # 将缺失值占比从高到低排序
    missing_data = pd.DataFrame({'Missing Ratio(%)':dataset_null})
    print(f'dataset含有缺失值的属性个数:{len(dataset_null)}')
    print(missing_data)
    

    分析获取三个表中每个表中有缺失值的属性个数以及该属性中的缺失值占比,输出结果如下图所示:
    在这里插入图片描述
    由结果明显可知:
    用户基本信息表user_data有2个属性含缺失值:pvalue_level(缺失54.24%)、new_user_class_level(缺失32.49%);
    广告基本信息表ads有1个属性含缺失值:brand(缺失29.09%);
    样本数据表dataset不含缺失值。
    所以只需对 user_data、ads 两个表进行缺失值填充。

    2. 缺失值填充

    缺失值填充说明:
    1.user_data表
    ‘pvalue_level’(消费档次:1低2中3高):通过KNN算法(基于K个最近邻的填充算法)进行预测填充;
    'new_user_class_level '(城市层次):该属性值为分类属性,对其进行众数填充。
    2.ads表
    ‘brand’(品牌ID):由于该数据为id类数据,填充其上下条数据的值,在本文中使用的是填充上一条数据的值。

    # 对 'new_user_class_level '进行众数填充
    from sklearn.impute import SimpleImputer   # 导入缺失值处理所需的库impute.SimpleImputer
    # 使用reshape(-1,1)对数据升维,原本是一维,但在sklearn当中的特征矩阵必须是二维的
    city_level = user_data.loc[:,'new_user_class_level '].values.reshape(-1,1)  # loc:对索引名进行切片   
    si = SimpleImputer(strategy = 'most_frequent')  # 实例化,使用众数填补
    user_data.loc[:,'new_user_class_level '] = si.fit_transform(city_level) # fit_transform一步训练导出结果
    user_data.info()
    

    输入结果如下图,可观察到 'new_user_class_level ’ 列中已经不含缺失值:
    在这里插入图片描述

    # 调整数据集user_data的列顺序:将'pvalue_level'列调至最后一列
    columns = ['userid', 'cms_segid', 'cms_group_id', 'final_gender_code', 'age_level',
           'shopping_level', 'occupation', 'new_user_class_level ','pvalue_level']
    user_data = user_data[columns]
    """
    按'pvalue_level'列值是否为空对数据集user_data进行分离
    """
    # 'pvalue_level'列值为空
    pvalue_null = user_data.loc[user_data['pvalue_level'].isnull().values == True]
    # 'pvalue_level'列值为空
    pvalue_nonull = user_data.loc[user_data['pvalue_level'].isnull().values == False]
    """
    对数据集pvalue_null和pvalue_nonull
    分离训练集和测试集
    X_train_user:'pvalue_level'列以外的,且'pvalue_level'列值不为0的部分
    y_train_user:'pvalue_level'列中的,且值不为0
    X_test_user:'pvalue_level'列以外的,且值为0
    y_test_user:'pvalue_level'列中的,且值为0
    """
    X_train_user,y_train_user = pvalue_nonull.iloc[:,:-1],pvalue_nonull.iloc[:,-1]
    X_test_user,y_test_user = pvalue_null.iloc[:,:-1],pvalue_null.iloc[:,-1]
    # 运用K最近邻(k-Nearest Neighbor,KNN)分类算法对'pvalue_level'列预测
    from sklearn.neighbors import KNeighborsClassifier    
    knn = KNeighborsClassifier(n_neighbors=3,weights='distance')  # 根据消费档次1浅2中3深分为3类,weights='distance'表示用欧氏距离进行相似度衡量
    knn.fit(X_train_user,y_train_user)   # 训练数据集
    y_test_user = knn.predict(X_test_user)   # 导出结果
    y_test_user   # 输出结果为:array([2., 2., 2., ..., 1., 2., 2.])
    
    """
    对KNN算法预测的数据进行整理合并填充,将整理后的数据写入新表user
    """
    y_test_user = pd.DataFrame(y_test_user)   # 将y_test_user由array转换成DataFrame结构
    y_test_user.columns = ['pvalue_level']  # 修改y_test_user的列名为'pvalue_level'
    X_test_user.reset_index(drop=True,inplace=True)  # 重置X_test_user索引
    # X_test_user.drop('index',axis=1,inplace=True) # 删除上述操作生成的原index索引列
    pvalue_null = pd.concat([X_test_user,y_test_user],axis=1)  # 横向合并X_test_user,y_test_user两个表
    user = pd.concat([pvalue_nonull,pvalue_null],ignore_index=False)   # 纵向合并pvalue_nonull,pvalue_null表为一个user新表,并重置索引值
    user.to_csv('D:/淘宝展示广告点击率预估数据集/user.csv',index=False,sep=',')  # 将user表数据写入user.csv文件中
    user = pd.read_csv('D:/淘宝展示广告点击率预估数据集/user.csv')  # 读取user数据
    user.info()
    

    输出结果如下,可以观察到user数据集已经不含缺失值:
    在这里插入图片描述

    # 用前一个数据对'brand'缺失的数据进行填充
    ads.fillna(method='pad',inplace=True)
    ads.info()
    

    在这里插入图片描述

    4.3 数据合并

    将dataset、user、ads三个表以表dataset为骨架,分别基于主键userid、adgroup_id进行合并封装,合并为新表data,以便同时构建用户特征广告特征来预测分析用户对广告点击概率。

    """
    合并表user、ads、dataset为ads_user_dataset
    将合并后的数据写入data.csv中并读取
    """
    print(f'dataset表的维度:{dataset.shape}')
    print(f'user表的维度:{user.shape}')
    print(f'ads表的维度:{ads.shape}')
    
    # 修改表dataset中列名user为userid,以便后面基于主键连接
    dataset.rename(columns={'user':'userid'},inplace=True)
    dataset.head()
    
    # 将数据集dataset与用户基本信息表user合并,基于主键userid,how='right'表示以右边表为基准连接
    user_dataset = pd.merge(user,dataset,on='userid',how='right')
    print(f'user_dataset表的维度:{user_dataset.shape}')
    
    # 将数据集与广告基本信息表ads合并,基于主键adgroup_id,how='right'表示以右边表为基准连接
    ads_user_dataset = pd.merge(ads,user_dataset,on='adgroup_id',how='right')
    print(f'ads_user_dataset表的维度:{ads_user_dataset.shape}')
    
    ads_user_dataset.to_csv('D:/淘宝展示广告点击率预估数据集/data.csv',index=False,sep=',')
    data = pd.read_csv('D:/淘宝展示广告点击率预估数据集/data.csv')
    

    合并后各表的数据维度如下图所示:
    在这里插入图片描述
    将用户特征数据user、广告特征数据ads以及样本数据dataset进行合并后,再对合并后的数据集data进行缺失值分析,代码如下:

    # 获取data每列的缺失值占比
    data_null = data.isnull().sum()/len(dataset)*100
    data_null = data_null.drop(data_null[data_null==0].index).sort_values(ascending=False)     # 将缺失值占比从高到低排序
    missing_data = pd.DataFrame({'Missing Ratio(%)':data_null})
    print(f'dataset含有缺失值的属性个数:{len(data_null)}')
    print(missing_data)
    

    在这里插入图片描述
    根据输出结果可知:data中共含有8个属性的缺失值,且这8个含缺失值的属性全都为用户特征数据集user中的属性,同时这8个属性的缺失值占比均为5.81%。据此我们可以推断出应该是在样本数据data存在,但在用户特征表user中不存在这些缺失值的userid。
    因此这些含有缺失值的数据对我们的分析没有太大意义,且缺失占比较小,直接将含有缺失值的行删除即可。
    代码如下:

    # 删除data中含有缺失值的行,直接在原数据上操作
    data.dropna(axis=0, how='any',inplace=True)  
    

    再次输入上面获取data每列的缺失值占比的代码块,查看缺失值的处理情况,结果如下图:
    在这里插入图片描述
    输入data.shape查看删除缺失值后data的数据维度,得到结果:(1883809, 19)

    4.4 时间戳数据处理

    原数据提供的是时间戳形式,我们需要将其转换为日期和时间形式以便分析,从转换后的数据中分别提取日期、时间、小时组成三个新的特征列。

    # 将数据中的时间戳形式转换为日期和时间形式
    import datetime
    import time
    data['time_stamp']=pd.to_datetime(data['time_stamp'],unit='s')
    data['time_stamp']
    # 从转换后的数据中分别提取:日期、时间、小时,组成新的列
    data['date'] = data['time_stamp'].dt.date
    data['time'] = data['time_stamp'].dt.time
    data['hour'] = data['time_stamp'].dt.hour
    # 调整数据集data的列顺序:将'data'、'time'、'hour'这三列数据调至'time_stamp'列后
    columns = ['adgroup_id', 'cate_id', 'campaign_id', 'customer', 'brand', 'price',
           'userid', 'cms_segid', 'cms_group_id', 'final_gender_code', 'age_level',
           'shopping_level', 'occupation', 'new_user_class_level ', 'pvalue_level',
           'time_stamp', 'date', 'time', 'hour', 'pid', 'nonclk', 'clk']
    data = data[columns]
    

    在这里插入图片描述

    4.5 删除不需要的列

    # 删除列'time_stamp'、'time'以及'nonclk'
    data = data.drop(['time_stamp','time','nonclk'],axis=1)
    

    五、分析目标

    提高广告的点击率以实现精准营销
    在这里插入图片描述

    六、分析过程

    本文中画图主要基于Pyecharts库实现
    由于以下分析画图代码过长,将其放置在文末

    6.1 分析广告点击率的整体现状

    1. 分析整体广告点击占比

    根据数据显示,广告的整体点击量仅占展示量的4.94%,即广告的点击率为4.94%,可见很多广告在展示过程中并没有吸引到用户或者说没有投放到有需要的用户群体。
    在这里插入图片描述

    2. 分析几天中广告点击的变化情况

    根据数据显示,几天中广告的整体点击率水平在5%左右浮动,没有太大的波动。2017-05-05这一天广告的展示量与点击量很低,猜测有可能是因为数据采样不均匀导致,后续会重新进行验证分析。
    在这里插入图片描述

    6.2 分析用户的产品偏好

    分析筛选受用户欢迎的广告商品
    我们根据【广告被点击次数】进行分层,进而对现有的广告进行价值分析:
    <10:测试广告是否有价值以及商品对用户是否有吸引力阶段;
    10-20:进一步确认商品对用户有一定的吸引力,之前的点击并非偶然情况;
    20-50:确定商品确实对用户有一定的吸引力,进一步加大广告投放力度,测试广告是否能否为商品带来转化;
    50-100:投放的广告能为商品的转化带来一定的效果;
    >=100:投放的广告能为商品的转化带来一定不错的效果。

    在这里插入图片描述在这里插入图片描述

    结论:①随着广告点击次数的上升,广告的点击率也在逐步上升,即广告价值与广告点击率呈正比关系。
    ②低价值广告的占比达到整体广告的98.34%之多,而高价值广告仅占整体广告的0.08%,这说明在测试广告价值阶段广告费用被高度浪费。

    我们现阶段要分析筛选出【广告点击次数>=100】,加大力度进行投放,同时进一步对其主要的受众群体进行分析,定位其投放的用户方向,实现用更少的广告费用获取更大的商品转化。

    6.3 分析一天24小时中用户的活跃时间

    在这里插入图片描述
    结论:
    ① 凌晨0点-7点、正午12点-14点这两个时间段是广告投放点击的高峰,傍晚16点-20点这个时间段是广告投放点击的低峰;
    ② 凌晨0点-7点这段时间是连续的高点击率时间,可以在这个时间段加大广告的投放力度;
    ③ 正午12点-14点这个时间段正好是人们的午饭午休时间,所以刷手机点击广告的概率也会增高;
    ④ 其中17点、19点这两个时间点的广告点击率相对较高,这个时间点正好是下班高峰期,人们在下班路上正好刷手机点击广告,建议在18点-19点这个时间段可以适当的加大广告投放力度;
    ⑤ 晚上20:00-0:00期间虽然广告展示量逐渐增加,但是广告的点击率却没有随之增加,反而降低了,猜测是用户如果没有必须且明确购买的需求,大部分用户在这段时间可能更倾向于陪伴家人、煲剧、看电影等休闲节目。

    6.4 分析广告在不同资源位上的点击情况

    在这里插入图片描述
    结论:
    广告在资源位430548_1007上展示量较多,但是相对而言,资源位430539_1007上的广告点击率相对更高,建议可以加大在资源位430539_1007上的广告投放力度。

    6.5 分析广告的受众群体特征

    1. 分析整体的广告受众群体特征

    在这里插入图片描述
    在这里插入图片描述

    ① 广告展示的用户约60%主要集中在微群0,且点击率达到5%;其他有些微群id虽然点击率也很高,但是数据量较小,不足以充分说明;
    ② 用户的男女比例约为1:2,且女性用户的点击率达到5.03%,男性用户的点击率只有4.81%,猜想是女性用户的购物欲会更强一些,建议可以加大对女性用户的广告投放;
    ③ 用户中非大学生用户占绝对主体,且点击率相对大学生用户更高,这符合非大学生用户具有更为独立的经济能力猜想;
    ④ 年龄层级为3、4、5的占比相对较高,点击率分别为:4.85%、4.91%、5.15%,其他层级的点击率虽然高,但是数据量少,不足以说明;
    ⑤ 微群群体3、4、5这三个群体中用户占比较高,且点击率分别高达:4.98%、4.97%、5.28%,建议可以加大对微群群体3、4、5的用户投放力度;
    ⑥ 购物程度为深度的用户占主体,但点击率仅占4.88%,建议对这一部分用户投放其更为感兴趣的广告;
    ⑦ 消费档次为低、中两档的用户占主体,尤其中档用户居多,且低、中档的用户点击率分别为:4.99%、4.95%,而高档用户点击率仅占4.65%,建议可以加大在消费档次为中档用户中的投放力度;
    ⑧ 城市层次为2的用户占主体,且相对其他城市层次的用户点击率最高,为4.99%,建议可以着重投放城市层次2的用户。

    下面用雷达图展示整体主要的受众群体特征:
    在这里插入图片描述

    2. 根据不同广告商品分析获取不同的受众群体特征

    由于广告商品数目过多,就不一一进行分析,我们从查看点击量前10的广告,如下图所示:
    在这里插入图片描述
    我们选取其中广告点击量第一的广告,即:adgroup_id为118317进行主要受众特征分析。
    下图是adgroup_id为118317的点击用户特征分布饼图:
    在这里插入图片描述

    结论:
    adgroup_id为118317的主要受众特征为:

    特征名特征群体
    微群0
    cms_group8>9>7
    性别
    是否大学生
    年龄层次2>3>1
    购物程度深度
    消费档次中档>低档
    城市层次2

    因此,在投放广告118317时建议侧重对具有上述受众特征的用户进行投放。

    6.6 基于物品的协同过滤推荐

    1. 获取【投放效果不错的广告商品】中相似度高的广告商品
    adgroup_id与118317的相似度
    80520.054313
    792350.054313
    422560.054313
    298050.054313
    2805840.054313
    1697910.054313
    1700500.054313
    2035760.054313
    191870.054313
    2395660.038405
    2. 根据广告商品的相似度和已知的用户历史行为给用户生成推荐列表

    我们从点击广告118317的用户中筛选满足上述受众特征的用户,筛选出来的userid有:

    1007255, 359747, 387456, 888900, 267564, 1059836, 922603, 538653

    我们分别向这些用户生成推荐列表,则:

    387456的推荐列表1007255, 359747, 888900, 267564, 1059836, 922603, 538653 的推荐列表
    $1600电脑

    结论:建议向点击过广告118317的用户群体也尝试投放以下几个广告:150272、205887、42256 、203576、79235。

    七、分析结论

    1、 广告整体的点击率约4.94%,主要是由于低价值广告较多,影响了整体的广告点击率,建议可以从受用户欢迎的商品类目、商品品牌以及广告主、广告计划中筛选要投放的广告商品;
    2 、时间维度:
    ① 凌晨0点-7点是连续的用户点击的活跃时间,建议加大的这个时间段广告投放力度;
    ② 傍晚17点-19点之间正好是下班高峰期,猜想人们在回家途中刷手机看广告点击的可能性会加大,建议可以稍微增加这个时间段的广告投放力度;
    3、资源位430539_1007上的点击率为5.01%,较
    430548_1007资源位的点击率高,建议尝试在资源位430539_1007上进行投放;
    4、广告整体的受众群体是:
    微群0、cms_group为3、女性、非大学生、年龄层次为3/4、购物为深度、消费档次中低档为主、城市层次为2
    如果投放时暂时没有受众群体方向,可以先以这个受众方向为主进行投放
    5、我们以点击量最高的广告id为118317进行分析:
    ①主要受众群体为:
    男性、非大学生、年龄层次2、购物为深度、消费中档、城市层级2、微群0、cms_group为8。
    ②推荐相似广告id为:
    150272、205887、42256 、203576、79235。

    八、代码部分

    8.1 整体广告点击占比饼图

    # 生成点击数据列表
    counts = data.clk.value_counts()
    ratio = data.clk.value_counts()/len(data)*100
    data_clk = pd.DataFrame({'Count':counts, 'Ratio(%)':ratio})
    
    # 绘制饼图对广告整体点击情况进行可视化
    from pyecharts import options as opts
    from pyecharts.charts import Pie
    
    b=data['clk']
    b=b.value_counts()
    b=dict(b)
    b['无点击人数']=b.pop(0)
    b['点击人数']=b.pop(1)
    
    name=pd.DataFrame(b.keys())
    value=pd.DataFrame(b.values())
    name=name[0].tolist()
    value=value[0].tolist()
    words=list(zip(list(name),list(value)))
    
    h=list(zip( list(b.keys()),list(b.values())))
    pie = Pie(init_opts=opts.InitOpts(width="500px", height="320px"))
    pie.add("",words)
    pie.set_global_opts(title_opts=opts.TitleOpts(title="广告整体点击情况",pos_left="40%"),
                        legend_opts=opts.LegendOpts(pos_top="20%", pos_left="80%"))
    pie.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}({d}%)"))
    pie.render_notebook()
    

    在这里插入图片描述

    8.2 几天中广告点击的变化情况(柱形-折线图)

    data_date = data.groupby('date')['clk'].agg({
        '展示量':'count',
        '点击量':sum,
        '点击率':np.mean
    })
    
    # 建立《2017/05/05至2017/05/13的广告点击情况》的柱形-折线图
    from pyecharts import options as opts
    from pyecharts.charts import Bar, Line
    from pyecharts.faker import Faker
    
    name = data_date.index.tolist()
    v1 = data_date.展示量.tolist()
    v2 = data_date.点击量.tolist()
    v3 = ((data_date.点击率.values)*100).tolist()
    v3 = [round(i,2) for i in v3]
    
    bar = (
        Bar(init_opts=opts.InitOpts(width="680px", height="420px"))
        .add_xaxis(name)
        .add_yaxis("展示量", v1)
        .add_yaxis("点击量", v2)
        .extend_axis(
            yaxis=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value} %"), interval=1)
        )
        .set_series_opts(label_opts=opts.LabelOpts(is_show=True))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="2017/05/05至2017/05/13的广告点击情况",pos_left="18%"),
            yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value} "), max_=350000),
            legend_opts=opts.LegendOpts(pos_top="10%", pos_right="10%")
        )
        
    )
    
    line = Line().add_xaxis(name).add_yaxis("点击率", v3, yaxis_index=1)
    bar.overlap(line)
    bar.render_notebook()
    

    在这里插入图片描述

    8.3 各点击区间的广告点击情况(堆积柱形-折线图、饼图)

    data_adgroup = data.groupby('adgroup_id')['clk'].agg({
        '展示量':'count',
        '点击量':sum,
        '点击率':np.mean
    })
    data_adgroup['点击量区间'] = data_adgroup.点击量.values   # 添加新列用来分区间
    data_adgroup.sort_values(by='点击量',ascending=False)
    
    # 对所有广告点击量进行分段
    bins = [0,10,20,50,100,100000]
    labels = ['<10','10-20','20-50','50-100','>=100']
    data_adgroup['点击量区间'] = pd.cut(data_adgroup.点击量区间,bins=bins,labels=labels,right=False)
    data_adgroup.sort_values(by='点击量',ascending=False)
    
    data_adgroup_clk= data_adgroup.groupby('点击量区间').agg({
        '点击量':['count',sum],
        '展示量':sum
    })
    data_adgroup_clk.columns = ['广告量','点击量','展示量']
    data_adgroup_clk['点击率'] = data_adgroup_clk.点击量.values/data_adgroup_clk.展示量.values*100
    data_adgroup_clk
    

    在这里插入图片描述

    """
    利用堆积柱形图-折线图可视化分析各点击数区间的广告点击率情况
    """
    from pyecharts import options as opts
    from pyecharts.charts import Bar, Line, Scatter
    from pyecharts.faker import Faker
    
    name = data_adgroup_clk.index.tolist()
    
    v0 = data_adgroup_clk.展示量.tolist()
    v1 = (data_adgroup_clk.展示量-data_adgroup_clk.点击量).tolist()
    v2 = data_adgroup_clk.点击量.tolist()
    v3 = data_adgroup_clk.点击率.tolist()
    v3 = [round(i,2) for i in v3]
    v4 = data_adgroup_clk.广告量.tolist()
    b = dict(zip(name,v4))
    words=list(zip(name,v4))
        
    bar = (
        Bar(init_opts=opts.InitOpts(width="640px", height="460px"))
        .add_xaxis(name)
        
        .add_yaxis("无点击量", v1, stack="stack1", category_gap="60%")
        .add_yaxis("点击量", v2, stack="stack1", category_gap="60%")
    
        .extend_axis(
            yaxis=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value} %"), interval=1)
        )
        .set_series_opts(label_opts=opts.LabelOpts(position="right"))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="各点击数区间的广告点击率情况", pos_left="30%"),
            yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value}"), max_=2500000),
            legend_opts=opts.LegendOpts(pos_top="6%", pos_left="50%")
            
        )
    )
    line = Line().add_xaxis(name).add_yaxis("点击率", v3, yaxis_index=1)
    bar.overlap(line)
    bar.render_notebook()
    

    在这里插入图片描述

    """
    利用玫瑰图描绘点击用户所在的城市层次分布
    """
    from pyecharts import options as opts
    from pyecharts.charts import Pie
    pie = (
        Pie(init_opts=opts.InitOpts(width="666px", height="365px"))
        .add("", words, center=["48%", "62%"],radius=["40%", "75%"], rosetype="radius")
        .set_global_opts(title_opts=opts.TitleOpts(title="各点击数区间的广告在整体广告中的占比分布",pos_right="22%"),
                        legend_opts=opts.LegendOpts(pos_top="6%", pos_right="16%"))
        .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}({d}%)"))   
    )
    pie.render_notebook()
    

    在这里插入图片描述

    8.4 一天24小时中用户的活跃时间(堆积柱形-折线图)

    data_hour = data.groupby('hour')['clk'].agg({
        '展示量':'count',
        '点击量':sum,
        '点击率':np.mean
    })
    data_hour
    
    """
    利用堆积柱形图-折线图可视化分析一天(24小时)中用户的点击情况
    """
    from pyecharts import options as opts
    from pyecharts.charts import Bar, Line
    
    name = data_hour.index.tolist()
    
    v0 = data_hour.展示量.tolist()
    v1 = (data_hour.展示量-data_hour.点击量).tolist()
    v2 = data_hour.点击量.tolist()
    v3 = data_hour.点击率.tolist()
    v3 = ((data_hour.点击率.values)*100).tolist()
    v3 = [round(i,2) for i in v3]
    b = dict(zip(name,v2))
    words=list(zip(name,v2))
    
        
    bar = (
        Bar(init_opts=opts.InitOpts(width="1020px", height="480px"))
        .add_xaxis(name)
        .add_yaxis("无点击量", v1, stack="stack1", category_gap="80%")
        .add_yaxis("点击量", v2, stack="stack1", category_gap="80%")
        .extend_axis(
            yaxis=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value} %"), interval=1, min_ = 4.5, max_ = 5.2)
        )
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False, position="right"))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="一天(24小时)中用户的点击情况", pos_left="35%"),
            xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)),
            yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value} "), max_ = 180000),
            legend_opts=opts.LegendOpts(pos_top="6%", pos_left="55%")
        )
    )
    line = Line().add_xaxis(name).add_yaxis("点击率", v3, yaxis_index=1,markline_opts=opts.MarkLineOpts(data=[opts.MarkLineItem(type_="average")]),)
    bar.overlap(line)
    bar.render_notebook()
    

    在这里插入图片描述

    8.5 广告在不同资源位上的点击情况(堆积柱形图-折线图)

    """
    利用堆积柱形图-折线图可视化分析广告在不同资源位上的点击情况
    """
    data_pid = data.groupby('pid')['clk'].agg({
        '展示量':'count',
        '点击量':sum,
        '点击率':np.mean
    })
    data_pid
    
    from pyecharts import options as opts
    from pyecharts.charts import Bar, Line
    
    name = data_pid.index.tolist()
    
    v0 = data_pid.展示量.tolist()
    v1 = (data_pid.展示量-data_pid.点击量).tolist()
    v2 = data_pid.点击量.tolist()
    v3 = data_pid.点击率.tolist()
    v3 = ((data_pid.点击率.values)*100).tolist()
    v3 = [round(i,2) for i in v3]
    b = dict(zip(name,v2))
    words=list(zip(name,v2))
        
    bar = (
        Bar(init_opts=opts.InitOpts(width="620px", height="460px"))
        .add_xaxis(name)
        
        .add_yaxis("无点击量", v1, stack="stack1", category_gap="80%")
        .add_yaxis("点击量", v2, stack="stack1", category_gap="80%")
    
        .extend_axis(
            yaxis=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value} %"), interval=1)
        )
        .set_series_opts(label_opts=opts.LabelOpts(position="right"))
        .set_global_opts(
            title_opts=opts.TitleOpts(title="广告在不同资源位上的点击情况", pos_left="30%"),
            yaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(formatter="{value}"), max_=1500000),
            legend_opts=opts.LegendOpts(pos_top="6%", pos_left="50%")
            
        )
    )
    line = Line().add_xaxis(name).add_yaxis("点击率", v3, yaxis_index=1)
    bar.overlap(line)
    bar.render_notebook()
    

    在这里插入图片描述

    8.6 广告的受众群体特征

    from pyecharts import options as opts
    from pyecharts.charts import Radar
    
    data1 = [{"value": [0, 3, 2, 3, 2, 3, 0, 2], "name": "主要受众群体"}]
    # data2 = [{"value": [2, 6, 1, 1, 0, 2], "name": "开销分配"}]
    c_schema = [
        {"name": "微群", "max": 97, "min": 0},
        {"name": "cms_group", "max": 12, "min": 0},
        {"name": "性别(1男2女)", "max": 2, "min": 1},
        {"name": "年龄层次", "max": 6, "min": 0},
        {"name": "消费档次(1:低档,2:中档,3:高档)", "max": 3, "min": 1},
        {"name": "购物深度(1:浅层用户,2:中度用户,3:深度用户)", "max": 3, "min": 1},
        {"name": "是否大学生(1:是,0:否)", "max": 1, "min": 0},
        {"name": "城市层级", "max": 4, "min": 1},
    ]
    radar = (
        Radar()
        .set_colors(["#4587E7"])
        .add_schema(
            schema=c_schema,
            shape="circle",
            center=["50%", "50%"],
            radius="80%",
            textstyle_opts=opts.TextStyleOpts(color="#000"),
            angleaxis_opts=opts.AngleAxisOpts(
                min_=0,
                max_=360,
                is_clockwise=False,
                interval=5,
                axistick_opts=opts.AxisTickOpts(is_show=False),
                axislabel_opts=opts.LabelOpts(is_show=False),
                axisline_opts=opts.AxisLineOpts(is_show=False),
                splitline_opts=opts.SplitLineOpts(is_show=False),
            ),
            radiusaxis_opts=opts.RadiusAxisOpts(
                min_=0,
                max_=8,
                interval=2,
                splitarea_opts=opts.SplitAreaOpts(
                    is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
                ),
            ),
            polar_opts=opts.PolarOpts(),
            splitarea_opt=opts.SplitAreaOpts(is_show=False),
            splitline_opt=opts.SplitLineOpts(is_show=False),
        )
        .add(
            series_name="主要受众群体",
            data=data1,
            areastyle_opts=opts.AreaStyleOpts(opacity=0.1),
            linestyle_opts=opts.LineStyleOpts(width=1, color="#CD0000"),
        )
    
    )
    radar.render_notebook()
    

    在这里插入图片描述
    根据不同广告商品分析获取不同的受众群体特征:

    # 查看所有投放的广告并按点击量排序
    data_adgroup = data.groupby('adgroup_id')['clk'].agg({
        '展示量':'count',
        '点击量':sum,
        '点击率':np.mean
    })
    data_adgroup.sort_values(by='点击量',ascending=False).head(10)
    

    在这里插入图片描述

    # 查看所有投放的广告并按点击量排序
    data_adgroup = data.groupby('adgroup_id')['clk'].agg({
        '展示量':'count',
        '点击量':sum,
        '点击率':np.mean
    })
    data_adgroup.sort_values(by='点击量',ascending=False)  # adgroup_id为118317的广告点击量第一(展示量3474,点击量348,点击率10.02%)
    
    # 筛选adgroup_id为118317的广告
    data_118317 = data[data['adgroup_id']==118317]
    data_118317
    
    # 筛选【adgroup_id为118317】且【被点击】的广告
    data_118317_clk = data_118317[data_118317['clk']==1]
    data_118317_clk
    
    # 根据【adgroup_id】、【userid】这两列去重
    data_118317_clk.drop_duplicates(subset=['userid','adgroup_id'],keep='first',inplace=True)
    
    data_118317_cms = data_118317.groupby('cms_segid')['clk'].agg({
        '点击量':sum,
    })
    data_118317_cms_group = data_118317.groupby('cms_group_id')['clk'].agg({
        '点击量':sum,
    })
    data_118317_gender = data_118317.groupby('final_gender_code')['clk'].agg({
        '点击量':sum,
    })
    data_118317_age = data_118317.groupby('age_level')['clk'].agg({
        '点击量':sum,
    })
    data_118317_shopping = data_118317.groupby('shopping_level')['clk'].agg({
        '点击量':sum,
    })
    data_118317_occupation = data_118317.groupby('occupation')['clk'].agg({
        '点击量':sum,
    })
    data_118317_city = data_118317.groupby('new_user_class_level ')['clk'].agg({
        '点击量':sum,
    })
    data_118317_pvalue = data_118317.groupby('pvalue_level')['clk'].agg({
        '点击量':sum,
    })
    
    from pyecharts import options as opts
    from pyecharts.charts import Pie
    
    name_cms = data_118317_cms.index.tolist()
    for i in range(0,len(name_cms)):
        name_cms[i]=f'微群{name_cms[i]}'
    v_cms = data_118317_cms.点击量.tolist()
    b_cms = dict(zip(name_cms,v_cms))
    words_cms = list(zip(name_cms,v_cms))
    
    name_cms_group = data_118317_cms_group.index.tolist()
    # for i in range(0,13):
    #     name_cms_group[i]=f'cms_group{i}'
    v_cms_group = data_118317_cms_group.点击量.tolist()
    b_cms_group = dict(zip(name_cms_group,v_cms_group))
    words_cms_group = list(zip(name_cms_group,v_cms_group))
    
    name_gender = data_118317_gender.index.tolist()
    name_gender[0]='男'
    name_gender[1]='女'
    v_gender = data_118317_gender.点击量.tolist()
    b_gender = dict(zip(name_gender,v_gender))
    words_gender = list(zip(name_gender,v_gender))
    
    name_age = data_118317_age.index.tolist()
    for i in range(0,7):
        name_age[i]=f'年龄层次{i}'
    v_age = data_118317_age.点击量.tolist()
    b_age = dict(zip(name_age,v_age))
    words_age = list(zip(name_age,v_age))
    
    name_shopping = data_118317_shopping.index.tolist()
    name_shopping[0]='浅度'
    name_shopping[1]='中度'
    name_shopping[2]='深度'
    v_shopping = data_118317_shopping.点击量.tolist()
    b_shopping = dict(zip(name_shopping,v_shopping))
    words_shopping = list(zip(name_shopping,v_shopping))
    
    name_occupation = data_118317_occupation.index.tolist()
    name_occupation[0]='非大学生'
    name_occupation[1]='大学生'
    v_occupation = data_118317_occupation.点击量.tolist()
    b_occupation = dict(zip(name_occupation, v_occupation))
    words_occupation = list(zip(name_occupation, v_occupation))
    
    name_city = data_118317_city.index.tolist()
    for i in range(0,4):
        name_city[i]=f'城市层次{i+1}'
    v_city = data_118317_city.点击量.tolist()
    b_city = dict(zip(name_city, v_city))
    words_city = list(zip(name_city, v_city))
    
    name_pvalue = data_118317_pvalue.index.tolist()
    name_pvalue[0]='低档'
    name_pvalue[1]='中档'
    name_pvalue[2]='高档'
    v_pvalue = data_118317_pvalue.点击量.tolist()
    b_pvalue = dict(zip(name_pvalue, v_pvalue))
    words_pvalue = list(zip(name_pvalue, v_pvalue))
    
    def new_label_opts():
        return opts.LabelOpts( formatter="{b}: {c}({d}%)", position="inside")
    
    
    c = (
        Pie(init_opts=opts.InitOpts(width="980px", height="460px"))
        .add(
            "微群分布",
            words_cms,
            center=["10%", "30%"],
            radius=[40, 80],
            label_opts=new_label_opts(),
        )
        .add(
            "cms_group分布",
            words_cms_group,
            center=["35%", "30%"],
            radius=[40, 80],
            label_opts=new_label_opts(),
        )
        .add(
            "性别分布",
            words_gender,
            center=["60%", "30%"],
            radius=[40, 80],
            label_opts=opts.LabelOpts(formatter="{b}: {c}({d}%)", position="inside"),
        )
        .add(
            "年龄层次分布",
            words_age,
            center=["85%", "30%"],
            radius=[40, 80],
            label_opts=new_label_opts(),
        )
        .add(
            "购物深度分布",
            words_shopping,
            center=["10%", "70%"],
            radius=[40, 80],
            label_opts=new_label_opts(),
        )
        .add(
            "是否大学生分布",
            words_occupation,
            center=["35%", "70%"],
            radius=[40, 80],
            label_opts=new_label_opts(),
        )
        .add(
            "城市层次分布",
            words_city,
            center=["60%", "70%"],
            radius=[40, 80],
            label_opts=new_label_opts(),
        )
        .add(
            "消费档次分布",
            words_pvalue,
            center=["85%", "70%"],
            radius=[40, 80],
            label_opts=new_label_opts(),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(title="广告id为【118317】的点击用户特征分布", pos_left="30%"),
            legend_opts=opts.LegendOpts(
                type_="scroll", pos_top="6%", pos_left="0%", 
            ),
        )
        .set_series_opts(
            tooltip_opts=opts.TooltipOpts(
                trigger="item", formatter="{a} <br/>{b}: {c} ({d}%)"
            ),
        )  
    )
    c.render_notebook()
    

    在这里插入图片描述

    8.7 基于物品的协同过滤推荐

    # 筛选有点击的数据
    data_clk_1 = data[data['clk'] == 1]
    
    # 根据【adgroup_id】、【userid】这两列去重
    data_clk_1.drop_duplicates(subset=['userid','adgroup_id'],keep='first',inplace=True)
    
    # 选取【'userid', 'adgroup_id', 'clk'】三列数据
    columns = ['userid', 'adgroup_id', 'clk']
    data_clk_col = data_clk_1[columns]
    
    # 将数据写入.txt
    data_clk_col.to_csv('D:/淘宝展示广告点击率预估数据集/data_clk_col.txt',sep=',',index=False)
    
    f = open('D:/淘宝展示广告点击率预估数据集/data_clk_col.txt', "r", encoding="utf-8")
    dataSet = {}
    
    for line in f:
        userid, adgroup_id, clk = line.strip().split(",")
        dataSet.setdefault(userid, {})
        dataSet [userid][adgroup_id] = clk
    print(dataSet)
    dataSet.pop('userid')
    print('-'*60)
    print(dataSet)
    
    from math import sqrt
    import operator
    
    N={};#喜欢广告i的总人数
    C={};#喜欢广告i也喜欢广告j的人数
    for userid,item in dataSet.items():
        for i,score in item.items():
            N.setdefault(i,0)
            N[i]+=1
            C.setdefault(i,{})
            
            for j,scores in item.items():
                if j not in i:
                    C[i].setdefault(j,0)
                    C[i][j]+=1
                    
    print("---构造的共现矩阵---")
    print ('N:',N);
    print ('C:',C);
    
    # 计算广告与广告之间的相似矩阵
    W={};
    for i,item in C.items():
        W.setdefault(i,{});
        for j,item2 in item.items():
            W[i].setdefault(j,0);
            W[i][j]=C[i][j]/sqrt(N[i]*N[j]);
    print("---构造广告的相似矩阵---")
    print(W)
    
    # 查询【118317】的推荐产品机器相似度并将其转换为dataFrame格式
    recommend_118317 = pd.DataFrame([W['118317']]).T
    
    # 修改列名
    recommend_118317.rename(columns={0:'相似度'},inplace=True)
    
    # 按相似度倒序排序
    recommend_118317.sort_values(by='相似度',ascending=False).head(10)
    

    在这里插入图片描述

    # 获取118317中符合主要受众群体的用户
    data_118317_clk_people = data_118317_clk[(data_118317_clk['cms_segid']==0) & (data_118317_clk['cms_group_id']==8) 
                    & (data_118317_clk['final_gender_code']==1) & (data_118317_clk['occupation']==0)
                   & (data_118317_clk['age_level']==2) & (data_118317_clk['shopping_level']==3)
                   & (data_118317_clk['pvalue_level']==2) & (data_118317_clk['new_user_class_level ']==2)]
    data_118317_clk_people
    

    根据用户历史行为进行推荐在此处以userid为’387456’为例:

    rank={};
    for i,score in dataSet['387456'].items():#获得用户userid‘387456’点击广告历史记录
        for j,w in sorted(W[i].items(),key=operator.itemgetter(1),reverse=True)[0:3]:#获得与广告i相似的k个物品
            if j not in dataSet['387456'].keys():#该相似的广告不在用户userid的记录里
                rank.setdefault(j,0);
                rank[j]+=float(score) * w;
                
    recommend_to_387456 = sorted(rank.items(),key=operator.itemgetter(1),reverse=True)[0:10]
    recommend_to_387456 = pd.DataFrame(recommend_to_387456)
    
    # 修改列名
    recommend_to_387456.rename(columns={0:'adgroup_id'},inplace=True)
    recommend_to_387456.rename(columns={1:'用户点击的概率'},inplace=True)
    
    print("---推荐给用户【387456】----")
    recommend_to_387456
    

    在这里插入图片描述

    展开全文
  • 基于用户行为特征的使用逻辑回归模型预测广告点击率
  • 广告点击率预估是怎么回事?

    万次阅读 2017-06-02 10:12:25
    点击率预估是广告技术的核心算法之一,它是很多广告算法工程师喜爱的战场。一直想介绍一下点击率预估,但是涉及公式和模型理论太多,怕说不清楚,读者也不明白。所以,这段时间花了一些时间整理点击率预估的知识,...
  • 广告点击率预估中的特征选择

    千次阅读 2017-05-27 21:19:38
    博文《互联网广告综述之点击率系统》论述了互联网广告点击率系统,能够看到,当中的logistic regression模型是比較简单并且有用的,其训练方法尽管有多种,但目标是一致的。训练结果对效果的影响是比較大。可是...
  • 类似Google AdSense这样的定向广告投放系统在过去十年得到了长足的发展和进步,在定向广告投放系统中,机器学习方法在广告点击率预估扮演着重要角色。目前,广告点击率预估模型中的训练数据逐渐呈指数级增长,越来越...
  • 项目:广告点击预测评估

    千次阅读 2019-09-30 17:13:20
    背景:一方面有流量的企业希望最大化广告收益;另一方面需要流量的个体希望最小化广告投放成本但同时最大化效果,这就是一个博弈的过程。 目前市面上流行的百度信息流、微信朋友圈投广都是基于这类的博弈过程。你...
  • 【转载】微信公众号广告点击率预估效果优化_腾讯大数据 http://data.qq.com/article?id=29141.背景 点击率预估(pCTR)是广告投放过程中的一个重要环节,精准的点击率预估对于广告投放系统收益最大化具有重要意义。...
  • 广告点击率预测-项目介绍

    千次阅读 2016-07-15 16:55:30
    1、给定查询和用户信息后预测广告点击率 搜索广告是近年来互联网的主流营收来源之一。在搜索广告背后,一个关键技术就是点击率预测—–pCTR(predict the click-through rate),由于搜索广告背后的经济模型...
  • 使用python进行广告点击率的预测

    千次阅读 多人点赞 2019-04-14 16:55:48
    当前在线广告服务中,广告的点击率(CTR)是评估广告效果的一个非常重要的指标。 因此,点击率预测系统是必不可少...今天我们就来动手开发一个移动广告点击率的预测系统,我们数据来自于kaggle,数据包含了10天的Ava...
  • 广告点击率预测(kaggle)

    千次阅读 2019-11-29 07:14:01
    这个项目的主要的目的是通过给定的广告信息和用户信息来预测一个广告点击与否。 如果广告有很大概率被点击就展示广告,如果概率低,就不展示。 因为如果广告没有被点击,对双方(广告主、平台)来讲都没有好处。...
  • 行业分类-物理装置-一种广告点击率预测方法.zip
  • 提高广告点击率.doc

    2021-09-15 18:35:38
    提高广告点击率.doc
  • 该数据集包括训练集train.csv,训练集结果train_label.csv,预测集test.csv,以及结果的保存样式submission.csv。
  • kaggle 大赛 点击率预估 分析,GBDT+FFM,排名第一,非常好的分析

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 42,409
精华内容 16,963
关键字:

一般广告点击率