1. 问题背景

所要解决的问题是找到目标人群,精准投放营销广告。
用户画像,即用户信息标签化,就是企业通过收集与分析消费者社会属性、生活习惯、消费行为等主要信息的数据之后,完美地抽象出一个用户的商业全貌。所以基于用户画像建立分类模型来预测短信投放的目标用户。

2. 构造训练数据

有三部分数据:用户画像数据(199737765条)、营销汇总数据(472616840条)、登录数据(495517967条),最后要筛选出选定的一次短信营销活动中的用户,用该用户的用户画像数据作为训练集,目标变量为观察期内是否登录,登录为1,未登录为0。

2.1 用户画像数据

先来看看用户画像数据,存放在hive中dim_customer_marking表内。用户画像表共有368个字段,剔除已下线和停止刷新项目如大学生项目,并选择用户的固有属性,如:是否购买基金、是否是陆金所用户、是否是平安内勤员工,剔除金融产品中的细分类别,并根据业务逻辑选择重要特征。因为要将静默用户和近期活跃用户按一定比例选择作为目标投放用户,并且响应指标是看用户在观察期内是否登录,所以剔除用户画像表中登录信息。对于生活类消费和购买的理财产品有很多细分类别,也先剔除,只保留对这些大类是否交易过,最后筛选出认为比较重要的特征56个。

from pyspark import SparkConf, SparkContext
from pyspark.sql import HiveContext,Row
hiveContext = HiveContext(sc)
dim_data=sc.sequenceFile('/user/hive/warehouse/i8ji.db/dim_customer_marking')
dim_data=dim_data.map(lambda x:x[1].split("\x01")).map(lambda x:(x[0],x[4],x[7],x[14],x[23],x[24],x[26],x[29],x[31],x[33],x[46],x[47],x[48],x[49],x[50],x[51],x[52],x[53],x[54],x[55],x[56],x[57],x[66],x[89],x[94],x[96],x[117],x[118],x[122],x[127],x[141],x[142],x[143],x[144],x[146],x[148],x[149],x[180],x[181],x[261],x[262],x[263],x[275],x[276],x[277],x[278],x[279],x[280],x[289],x[306],x[335],x[336],x[337],x[340],x[341],x[342],x[343]))
dim_data1=hiveContext.createDataFrame(dim_data)

部分特征如下:

2.2 营销汇总数据

然后在营销数据汇总表dim_yx_customer_base_new中,选择短信营销,即令channel=’S’,并选择一次营销活动——【822砍价——短信营销第二波】,活动id为39010,即令campaign_id=39010。
营销数据汇总表为orc格式,用hiveContext.read.format(“orc”).load(path)来读写。

data=hiveContext.read.format("orc").load("/user/hive/warehouse/i8ji.db/dim_yx_customer_base_new")
train_data=data.filter("channel='S' and campaign_id=39010").select("customer_id")

2.3 登录数据

在用户登录表mid_dim_cust_ex_login中取出在2017年8月22日至9月5日(观察期)内登录的用户,去重,并赋值为1(为后面构造目标变量做准备)。

login_data=sc.textFile("/user/hive/warehouse/i8ji.db/mid_dim_cust_ex_login")
login_data=login_data.map(lambda x:x.split("\x01"))
login_user=login_data.map(lambda x:Row(customer_id=x[0],login_time=x[1]))
login_user1=hiveContext.createDataFrame(login_user)
login_user2=login_user1.filter("login_time>'2017-08-22' and login_time<'2017-09-05'").select("customer_id")
login_user3=login_user2.distinct()
login_user4=login_user3.rdd.map(lambda x:Row(customer_id=x[0],y=1))
login_user5=hiveContext.createDataFrame(login_user4)

2.4 构造训练集

先取出该次营销活动用户的用户画像数据,即用户两个数据表按customer_id做“inner” join。

train=dim_data1.join(train_data,train_data.customer_id==dim_data1._1,'inner')
train1=train.drop('customer_id')

然后构造目标变量,将上述数据与登录数据按customer_id做left_join,空值填充为0。

train2=train1.join(login_user5,train1._1==login_user5.customer_id,'left_outer')
train3=train2.na.fill({'y':0})
train4=train3.drop('customer_id')

最后将训练集保存到hive。

train4.saveAsTable('trainmm',mode='overwrite')

3. 数据处理

先来看下训练集大小和正负样本数量。得到训练集有284681条

df=hiveContext.read.load('/user/hive/warehouse/trainmm')
df.count()
df.groupBy('y‘).count().show()

如下表所示,正负样本分布比较均衡:

y count
0 170103
1 114578

静默用户分布:

_40 count
0 245213
1 39468

将训练集中56个特征按照离散变量和连续变量分类处理。基本方法是做缺失值、异常值处理、离散化、数据变换(标准化、归一化、对数变换)等。

3.1 离散变量

首先看各变量的缺失情况(注意,实际上不是空值,而是空字符串“)。

缺失变量 count
_2 55020
_3 55022
_10 39645
_24 117465
_29 13
_30 13
_31 258194
_32 258194
_33 258217
_34 258217
_35 258217
_36 284681
_37 284681
_43 74610
_44 74610
_45 74610
_46 74610
_47 74610
_48 74610
_49 281167
_51 9180
_52 9180
_53 9180
_54 12650
_55 84406
_56 84406
_57 84406

_31、_32、_33、_34、_35、_36、_37、_49,这8个变量的缺失数量在90%以上,所以删除这些变量,其他有缺失值的变量中一般将缺失值填充为-1,还有下面的特殊情况。
将生日所在年份、注册时间、首次登陆时间转变为年龄或距营销日期天数。并且,将定性的特征变成数值型,定性特征如下:

_2 count
F 124404
M 105257
55020
_44 count
00.积分段0元 80185
09.积分段[50,100)元 7309
13.积分段大于等于1000元以上 3729
06.积分段[10,20)元 8870
07.积分段[20,30)元 5335
08.积分段[30,50)元 6148
05.积分段[5,10)元 11462
11.积分段[200,500)元 6563
01.积分段(0,0.2)元 27229
12.积分段[500,1000)元 3457
10.积分段[100,200)元 6700
04.积分段[2,5)元 12442
02.积分段[0.2,1)元 21785
74610
03.积分段[1,2)元 8857
_48 count
MOB_m0 502
MOB_m1 31166
MOB_m2 18811
old 159592
74610

连续变量

所有连续变量的描述统计信息,可以看到有几个特征的最大值非常大,该特征的含义均为多天的交易金额或理财账户余额,所以比较合理,不认为是异常值。

summary _8 _9 _11 _12 _13 _14 _15 _16 _17 _18
count 284681 284681 284681 284681 284681 284681 284681 284681 284681 284681
mean 4.88 0.18 0.65 2840.11 884.99 0.46 2.63 12087.80 1852.43 1.84
stddev 7.36 0.74 5.13 29635.17 9656.47 4.94 15.69 81661.25 15482.61 14.99
min 0 0 0 0.0 0.0 0 0 0.0 0.0 0
max 99 9 99 9999.91 9999.66 99 99999999 99993.74 99
summary _19 _20 _21 _22 _25 _26 _27 _28 _50
count 284681 284681 284681 284681 284681 284681 284681 284681 284681
mean 8.07 36595.32 3059.08 5.90 38021.46 69.24 2913.35 5.91
stddev 40.34 188195.69 22527.65 37.97 123498.09 86.66 29701.63 422.50 766.76
min 0 0.0 0.0 0
max 993 99998.0 9999.87 993 9999 99 99967.03 996.0 8027.38

然后查看缺失值,只有5个特征有缺失值,缺失数量如下,删除_25、_26和_50特征。_27和_28因为是余额,所以缺失可能是因为用户没有办理这项业务,所以将缺失值填充为0。

缺失变量 count
_25 233374
_26 271181
_27 61383
_28 39645
_50 260242

数据处理如下:

df1=df.drop('_25')
df1=df1.drop('_26')
df1=df1.drop('_31')
df1=df1.drop('_32')
df1=df1.drop('_33')
df1=df1.drop('_34')
df1=df1.drop('_35')
df1=df1.drop('_36')
df1=df1.drop('_37')
df1=df1.drop('_49')
df1=df1.drop('_50')
from datetime import datetime
d=df1.rdd.map(lambda x:[x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15],x[16],x[17],x[18],x[19],x[20],x[21],x[22],x[23],x[24],x[25],x[26],x[27],x[28],x[29],x[30],x[31],x[32],x[33],x[34],x[35],x[36],x[37],x[38],x[39],x[40],x[41],x[42],x[43],x[44],x[45],x[46]])
mm={u'MOB_m0':0,u'MOB_m1':1,u'MOB_m2':2,u'old':3}
m={u'00.积分段0元':0,u'01.积分段(0,0.2)元':1,u'02.积分段[0.2,1)元':2,u'03.积分段[1,2)元':3,u'04.积分段[2,5)元':4,u'05.积分段[5,10)元':5,u'06.积分段[10,20)元':6,u'07.积分段[20,30)元':7,u'08.积分段[30,50)元':8,u'09.积分段[50,100)元':9,u'10.积分段[100,200)元':10,u'11.积分段[200,500)元':11,u'12.积分段[500,1000)元':12,u'13.积分段大于等于1000元以上':13}
def f1(x):if [1]=='M':x[1]=0elif x[1]=='F':x[1]=1else:x[1]=-1if x[2]=='':x[2]=1980if x[9]=='':x[9]='2017-08-22 00:00:00'         x[2]=2017-int(x[2])x[3]=(datetime.strptime('2017-08-22','%Y-%m-%d')-datetime.strptime(x[3],'%Y-%m-%d %H:%M:%S')).daysx[9]=(datetime.strptime('2017-08-22','%Y-%m-%d')-datetime.strptime(x[9],'%Y-%m-%d %H:%M:%S')).daysif x[23]=='':x[23]=-1for j in range(24,26):if x[j]=='':x[j]=0for j in range(26,46):if x[j]=='':x[j]=-1for k,v in mm.items():if x[38]==k:x[38]=vfor k,v in m.items():if x[34]==k:x[34]=vx=list(map(float,x))return x
data=d.map(lambda x:f1(x))

算法实现

先比较一下后面要用到的两种算法,只看性能方面,不讲具体原理(参考了MLlib文档)

Gradient-Boosted Trees vs. Random Forests:

GDBT和RF都是基于树的集成学习的算法,但训练过程不同,下面是几个它们的不同点:

  • GDBT一次训练一棵树,所以训练时间比RF要长。RF可以并行训练多棵树。另外,训练GDBT比RF时使用更少的树是有意义的,并且树越少花费时间越短。
  • RF更不易于过拟合。训练越多的树时RF会减少过拟合的可能性,但GDBT会增加过拟合。(换做统计语言就是,RF通过使用更多的树减少方差,而GBDT通过使用更多的树减少偏差。
  • RF更容易调参,因为模型性能随树的个数单调递增(但是如果树的个数变得过大,性能可能会开始变差)。
    总之,两个算法都很有效,如何选择要基于实际的数据集。

Random Forests

不需要对特征标准化
训练过程引入两个随机性:

  • 每次迭代对原始训练集子采样,每次得到不同的训练集(a.k.a. bootstrapping)。
  • 每棵树划分节点时随机选择的特征的子集作为候选划分特征

Usage tips

首先看最重要的两个参数,调节它们通常会提高性能:

  • numTrees: 树的个数。增加树的个数会减少预测的方差,提高模型的准确率。训练时间呈线性增加。
  • maxDepth: 每棵树的最大深度。增加树深度会使模型更美好和强大,但是会花费更多时间去训练,并且容易过拟合。通常,可以接受训练RF时比训练单颗决策树使用更大深度的树。一棵树比RF更易过拟合(因为平均多棵树会减少方差)。
    还有两个参数通常不需要调节。但是,可以调节它们来提高训练的速度。
  • subsamplingRate: 训练每棵树的训练集大小,是原始训练集的一部分。推荐使用默认值(1.0),减少这个比例可以提高训练的速度。
  • featureSubsetStrategy: 每棵树划分节点时使用的候选特征的个数。减少这个数量可以提高训练的速度,但如果值太低有时会影响效果。

Gradient-Boosted Trees

同样不需要对特征标准化
Losses
每个损失函数的适用情况,注意:每个损失函数只适应于分类或回归中的一种。

Loss Task Description
Log Loss Classification Twice binomial negative log likelihood.
Squared Error Regression Also called L2 loss. Default loss for regression tasks.
Absolute Error Regression Also called L1 loss. Can be more robust to outliers than Squared Error.

Usage tips:

  • loss: 不同的损失函数会得到不同的结果,具体用哪个取决于数据集。
  • numIterations: 设置集成中树的个数。每次迭代会产生一棵树。增加这个值使模型性能更优,提高训练集准确率。但如果值太大,测试集准确率降低。
  • learningRate: 学习速率,即步长。不该调节该参数。如果算法表现不稳定,减小这个值可能会提高稳定性。

模型评估及选择

最后就到建模这一步了,要做交叉验证来看模型效果和模型调优,一般是将训练集分成两部分,一部分用于训练我们需要的模型,另外一部分数据上看我们预测算法的效果。

from pyspark.mllib.regression import LabeledPoint
train=data.map(lambda x:LabeledPoint(x[-1],x[1:46]))
(trainingData, testData) = train.randomSplit([0.7, 0.3])

然后训练模型,这里分别用了随机森林和GDBT,看一下在训练集上预测的准确率。
maxDepth均设为10,RF调节numTrees参数,GBDT调节numIterations参数

from pyspark.mllib.tree import RandomForest, RandomForestModel
from pyspark.mllib.tree import GradientBoostedTrees, GradientBoostedTreesModel
from pyspark.mllib.util import MLUtils
r1=[]
for i in [3,10,40,60,80]:model = GradientBoostedTrees.trainClassifier(trainingData,categoricalFeaturesInfo={},numIterations=i,maxDepth=10)predictions = model.predict(testData.map(lambda x: x.features))labelsAndPredictions = testData.map(lambda lp: lp.label).zip(predictions)accuracy = 1-labelsAndPredictions.filter(lambda (v, p): v != p).count() / float(l)r1.append(accuracy)r2=[]
for i in [50,100,150,200]:model = RandomForest.trainClassifier(trainingData, numClasses=2, categoricalFeaturesInfo={}, numTrees=i, featureSubsetStrategy="auto",impurity='gini', maxDepth=10, maxBins=32)predictions = model.predict(testData.map(lambda x: x.features))labelsAndPredictions = testData.map(lambda lp: lp.label).zip(predictions)accuracy = 1-labelsAndPredictions.filter(lambda (v, p): v != p).count() / float(l)r2.append(accuracy)

随机森林调参:

numTrees 50 100 150 200
accuracy 0.8443473768258889 0.84653139824338919 0.84383072659809311 0.84445305528157433

GBDT调参:

numIterations 3 10 40
accuracy 0.84748250434455874 0.8509464092809168 0.85233197125546001

GDBT以时间换性能。

总结

  • 活跃用户和静默用户按一定比例作为目标用户,所以分别训练模型
  • 按不同类别的营销活动,分别筛选特征、建模
  • 重新筛选特征、构造特征、交叉特征
  • 不盲目调参,理解参数对预测的影响,深入理解算法

基于用户画像的精准营销相关推荐

  1. 基于用户画像的精准营销决策建议

    读研期间,最大的收获就是在导师的引导下,多次带领团队参与政府及公司的合作项目.在项目中增长了实践经验,积累了相关统计知识.学习了模型构建方法及算法编写的优化方式. 趁着现在不忙,把部分可公开.不涉密的 ...

  2. 用户画像_什么是“用户画像”?如何利用用户画像进行精准营销?

    1.什么是"用户画像" 所谓的用户画像,简单来说就是根据用户社会属性.生活习惯和消费行为等信息而抽象出的一个标签化的用户模型. 用户画像,即用户信息标签化,就是企业通过收集与分析消 ...

  3. 品牌数字化升级,如何借力用户画像实现精准营销? - whale 帷幄

    你是否有过这样的经历:当在购物网站有过一次购物或者搜索后,网站会为你推送各种同类型商品或者互补商品:当成为某品牌的注册会员后,特殊的日子(比如生日.会员日)会收到品牌商发来的祝福短信以及优惠券:当打开 ...

  4. 客户人群画像分析 客户进行用户画像实现精准营销- Whale帷幄

    你是否有过这样的经历:当在购物网站有过一次购物或者搜索后,网站会为你推送各种同类型商品或者互补商品:当成为某品牌的注册会员后,特殊的日子(比如生日.会员日)会收到品牌商发来的祝福短信以及优惠券:当打开 ...

  5. 找出你的高价值潜在用户 - 通过归因分析实现用户画像和精准营销

    在之前的博客文章 为什么你的用户转化率不高?--新媒体运营转化效果渠道归因分析中,我们讲到 新媒体运营用户转化相关的指标以及目标追踪,以及相关的渠道归因分析.在本篇文章中,我们一起来看看,如何通过 K ...

  6. 【干货】用户画像和精准化平台系统实践.pdf(附下载链接)

    今天给大家带来一份干货资料<用户画像和精准化平台系统实践.pdf>,本文档共48页,包含如下五大部分: 1.平台总体介绍: 2.用户标签画像和标签体系: 3.基于画像的相关系统和投放: 4 ...

  7. 基于大数据的精准营销与应用场景

    基于大数据的精准营销与应用场景 2015年08月11日 大数据 大数据营销时代来临 营销学领域过去半个多世纪的发展让我们见证了从"以产品为中心"到"以客户为中心" ...

  8. Django基于用户画像的电影推荐系统源码(项目源代码)

    一.项目介绍 公众号:yk 坤帝 获取全部源代码 本系统是以Django作为基础框架,采用MTV模式,数据库使用MongoDB.MySQL和Redis,以从豆瓣平台爬取的电影数据作为基础数据源,主要基 ...

  9. 基于用户画像的PythonDjango框架的电影推荐系统设计与实现

    目录 BiSheServer 1 1.项目介绍 1 2.系统架构图 1 3.系统模块图 1 4.目录结构及主要文件说明 1 5.配置文件说明 3 [DEFAULT] 3 [DATEBASE] 3 [R ...

最新文章

  1. java 内存类_Java学习——类的生命周期和内存
  2. python 语言教程(4)元组
  3. 【博客话题】技术生涯中的出与入
  4. 记录使用websocket时因为Sec-Websocket-Protocol遇到的一个问题
  5. HTTP状态码:400\500 错误代码
  6. Spark2内存调优总结 - 内存划分 与 内存计算 与 调参方式
  7. Oracle高可用概述(HA与RAC的关系解惑)
  8. 第12章第1讲位运算符与表达式
  9. 《深入浅出struts》读书笔记(3)
  10. 基于51单片机的超声波倒车雷达防撞系统 proteus仿真 LCD1602显示
  11. 精心梳理二十二道常见SSM面试题(带答案)
  12. 【文献学习】DeepReceiver: A Deep Learning-Based Intelligent Receiver for Wireless Communications in the Ph
  13. python实现整数反转
  14. 数据分析-人群画像和目标群体分析
  15. 工作组和域的概念及辨析
  16. 气压曲线软件 android,GPS气压海拔测量
  17. 什么是独享住宅IP代理?为什么爬虫适合用住宅http代理?
  18. 部署Python的框架下的web app的详细教程
  19. 使用clion搭建CUDA开发环境
  20. http://www.ithao123.cn/content-1432166.html

热门文章

  1. eul for Mac(菜单栏系统监控工具) v1.5中文版
  2. c语言检测HDMI热插拔,玩转HDMI2.1 源端测试之【入门基础篇】
  3. 高等数学:第四章 不定积分(2)分部积分法 特殊类型函数的积分
  4. Django添加favicon.ico图标
  5. 牛逼!JetBrains 又出了一款编程神器!协同编程!
  6. PCB工程师不得不看:超级实用AD常用快捷键总结
  7. matlab2c使用c++实现matlab函数系列教程-inv函数
  8. ubuntu18.04+pcl1.8:运行visualization可视化程序,vtk6.3报错,vtk版本过低需重新安装对应版本vtk7.1.1
  9. Word文档带有权限密码怎么办?
  10. 冷水机组相关温度、压力参数意义详解