最近运营部门希望我们帮助他们找出合适的短信营销对象,通过短信营销能够提高他们的投资者再次投资转化率,那么如何找到这个精准人群就是我们部门必须出手做的事情了?但是从几百万投资者中找出最近要复投的用户,这数据挖掘工作究竟该如何入手呢?不着急,我先上结果给大家先看看。

(这是我5月9日给出的一波预测会复投的新用户ID,当日下午做营销,5月11日晚20:00的结果)

(这是业务部门5月8日做的一波新用户ID营销,5月11日晚20:00的结果)

两者转化率相差5倍!

当然,我们的针对人群是不同的,现在就让我对这次数据挖掘项目做一个回顾吧!

第一步:听懂需求(这一步是数据挖掘项目的最关键步骤,万事开头难,就难在理解需求)

首先我们来听一下业务部门的需求:“这个月新交易用户比其他月份多,我们如何留住这些用户?”或者是“这个月交易压力比较大,我们必须让更多用户做更多次的交易。”

那我们重点讲一下第一个需求:“这个月新交易用户比其他月份多,我们如何留住这些用户?”这个需求的潜在意义是什么?

运用5W1H方法,我们可以得知问题的主要变量:

who:新交易用户

what:留住新交易用户

when:让新用户这个月留住

why:新用户如果本月不交易,那么前面的推广费用就打了水漂

where:让新用户留在本平台上

how:如何(在这个月把尽可能多的新用户留在本平台继续交易)

最终我对这个问题的定义就是,如何找到这个月可能会复投的新用户(上个月新交易用户),对他们进行短信营销促进他们这个月投资?

第二步:用数据解构需求,做好建模分析前的准备

根据问题的主要自变量,我们找出具体的对应数据集:2016年5月至2017年4月每月新交易用户(12个月),每个月的用户数据维度我都从当月取值,保证新交易用户数据不影响目标变量;(在寻找自变量的过程中,还吃了不少亏,不是所有变量都能做模型输入的,需要较长的时间做好数据清洗,比如性别、地域及交易时间等)

那么模型的目标变量该如何确定呢?说一下我在确定目标变量寻找上的误区,供大家参考。

我第一次找的目标变量是本月数据表中上月新用户的第二次交易,后来发现有很多新用户的第二次交易就在上月,目标变量不准确;

第二次我找了本月数据表中上月新用户第二次到第五次交易时间,并且还设定了第二次到第五次交易时间在本月才为目标,但是后来仍然发现,有上月新用户上月就交易超过5次,所以目标变量依然不准确;

第三次我找了本月数据表中上月新用户最近两次交易时间,并且还设定了最近两次交易时间在本月才为目标,至此才把目标变量确定下来。

后面业务部门又提出了新需求,说是是否能找出不给补贴就重复交易的用户,后来我针对这个目标又增加了一个目标变量,无补贴重复交易用户,这是后话。至于如何取该业务需求的目标变量,大家可以探讨一下哈。

第三步:测试建模,调参

把前面的数据都准备好之后,剩下的就是选择模型调试参数,看模型测试结果了,我一般使用xgboost模型做预测,代码分成两部分如下:

1、初始化及调参

library(Matrix)
library(xgboost)
library(Ckmeans.1d.dp)
#library(kknn)
#library(rminer)
wk1<-read.csv('d:/Rdata/zjd/lyhft/wkft/164-165.csv',na.string='NA',header=T)
wk2<-read.csv('d:/Rdata/zjd/lyhft/wkft/165-166.csv',na.string='NA',header=T)
wk3<-read.csv('d:/Rdata/zjd/lyhft/wkft/166-167.csv',na.string='NA',header=T)
wk4<-read.csv('d:/Rdata/zjd/lyhft/wkft/167-168.csv',na.string='NA',header=T)
wk5<-read.csv('d:/Rdata/zjd/lyhft/wkft/168-169.csv',na.string='NA',header=T)
wk6<-read.csv('d:/Rdata/zjd/lyhft/wkft/169-1610.csv',na.string='NA',header=T)
wk7<-read.csv('d:/Rdata/zjd/lyhft/wkft/1610-1611.csv',na.string='NA',header=T)
wk8<-read.csv('d:/Rdata/zjd/lyhft/wkft/1611-1612.csv',na.string='NA',header=T)
wk9<-read.csv('d:/Rdata/zjd/lyhft/wkft/1612-171.csv',na.string='NA',header=T)
wk10<-read.csv('d:/Rdata/zjd/lyhft/wkft/171-172.csv',na.string='NA',header=T)
wk11<-read.csv('d:/Rdata/zjd/lyhft/wkft/172-173.csv',na.string='NA',header=T)
wk12<-read.csv('d:/Rdata/zjd/lyhft/wkft/173-174.csv',na.string='NA',header=T)
wktest<-read.csv('d:/Rdata/zjd/lyhft/wkft/174.csv',na.string='NA',header=T)
wkft<-rbind(wk1,wk2,wk3,wk4,wk5,wk6,wk7,wk8,wk9,wk10,wk11,wk12)
#初始化数据集,设定训练集、预测目标、测试集
wkft1<-cbind(wkft[,3:11],wkft[,13:24],wkft[,33])
wkft2<-cbind(wkft[,3:11],wkft[,13:24],wkft[,34])
#wkft3<-cbind(wkft[,3:11],wkft[,13:24],wkft[,35])
#wkft4<-cbind(wkft[,3:11],wkft[,13:24],wkft[,36])
wktest1<-cbind(wktest[,3:11],wktest[,13:24])
wkft12=Matrix(data.matrix(cbind(wkft1)),sparse=T)
wkft22=Matrix(data.matrix(cbind(wkft2)),sparse=T)
#wkft32=Matrix(data.matrix(cbind(wkft3)),sparse=T)
#wkft42=Matrix(data.matrix(cbind(wkft4)),sparse=T)
wktest2=Matrix(data.matrix(cbind(wktest1)),sparse=T)
#对训练集和测试集设定可计算的格式
wktrain1=xgb.DMatrix(data=wkft12[,1:21],label=wkft12[,22])
wktrain2=xgb.DMatrix(data=wkft22[,1:21],label=wkft22[,22])
#wktrain3=xgb.DMatrix(data=wkft32[,1:21],label=wkft12[,22])
#wktrain4=xgb.DMatrix(data=wkft42[,1:21],label=wkft22[,22])
dtest=xgb.DMatrix(data=wktest2[,1:21])
#subsam=c(0.5,0.7,0.9)
#colsam=c(0.5,0.7,0.9)
weight=c(1,3,5)
depth=c(10,12,15)
eta=c(0.4,0.5,0.6)
b1<-matrix(0,1,7)
for (i in 1:length(weight)){
  for (m in 1:length(depth)){
    for (n in 1:length(eta)){
      #测试模型并调整参数
      model=xgb.cv(booster='gbtree',
             objective='binary:logistic',
             scale_pos_weight=6.8125,
             gamma=0.1,
             lambda=1210,
             subsample=0.7,
             set.seed=10000,
             colsample_bytree=0.5,
             min_child_weight=weight[i],
             max_depth=depth[m],
             eta=eta[n],
             data=wktrain1,
             nrounds=1000,
             metrics='error',
             nfold=10,
             verbose=1,
             showsd=1,
             print.every.n=100,
             #nthread=100
             )
      b=cbind(weight[i],depth[m],eta[n],which.min(model$train.error.mean),min(model$train.error.mean),which.min(model$test.error.mean),min(model$test.error.mean))
      b1=rbind(b1,b)
      }}}
b2<-matrix(0,1,7)
for (i in 1:length(weight)){
  for (m in 1:length(depth)){
    for (n in 1:length(eta)){
      model=xgb.cv(booster='gbtree',
             objective='binary:logistic',
             scale_pos_weight=6.8125,
             gamma=0.1,
             lambda=1210,
             subsample=0.7,
             set.seed=10000,
             colsample_bytree=0.5,
             min_child_weight=weight[i],
             max_depth=depth[m],
             eta=eta[n],
             data=wktrain2,
             nrounds=1000,
             metrics='error',
             nfold=10,
             verbose=1,
             showsd=1,
             print.every.n=100,
             #nthread=100
      )
      b=cbind(weight[i],depth[m],eta[n],which.min(model$train.error.mean),min(model$train.error.mean),which.min(model$test.error.mean),min(model$test.error.mean))
      b2=rbind(b2,b)
    }}}
b1<-b1[-1,]
b2<-b2[-1,]
write.csv(b1,file = "d:/Rdata/zjd/lyhft/wkft/wkcs1.csv")
write.csv(b2,file = "d:/Rdata/zjd/lyhft/wkft/wkcs2.csv")

2、根据最优测试方案设定参数跑出模型

#根据测试模型设定正式参数并跑出模型
model.x1<-xgb.train(
  booster='gbtree',
  objective='binary:logistic',
  scale_pos_weight=6.8125,
  gamma=0.1,
  lambda=1210,
  subsample=0.7,
  set.seed=5000,
  colsample_bytree=0.3,
  min_child_weight=5,
  max_depth=15,
  eta=0.3,
  data=wktrain1,
  nrounds=5000,
  metrics='error',
  nfold=10
  #verbose=1,
  #showsd=1,
  #print.every.n=1,
  #nthread=100
)
model.x2<-xgb.train(
  booster='gbtree',
  objective='binary:logistic',
  scale_pos_weight=6.8125,
  gamma=0.1,
  lambda=1210,
  subsample=0.7,
  set.seed=5000,
  colsample_bytree=0.3,
  min_child_weight=5,
  max_depth=15,
  eta=0.3,
  data=wktrain2,
  nrounds=5000,
  metrics='error',
  nfold=10
  #verbose=1,
  #showsd=1,
  #print.every.n=1,
  #nthread=100
)

3、预测复投人群并画出各维度权重

#预测测试集目标变量
pred1<-predict(model.x1,dtest)
pred2<-predict(model.x2,dtest)
#pred3<-predict(model.x3,dtest)
#pred4<-predict(model.x4,dtest)
#存储模型
xgb.save(model.x1,'d:/Rdata/zjd/lyhft/wkft/2017041')
xgb.save(model.x2,'d:/Rdata/zjd/lyhft/wkft/2017042')
#xgb.save(model.x3,'d:/Rdata/zjd/lyhft/wkft/2017043')
#xgb.save(model.x4,'d:/Rdata/zjd/lyhft/wkft/2017044')
#xg5<-xgb.load('d:/Rdata/zjd/lyhft/wkft/201704')
#导出测试数据及测试结果
a<-cbind(wktest,pred1,pred2)
write.csv(a,file = "d:/Rdata/zjd/lyhft/wkft/wkftxg.csv")
# 计算特征重要性矩阵
model <- xgb.dump(model.x1, with.stats = T)
names<-dimnames(wkft12[,-22])[[2]]
importance_jf <- xgb.importance(names, model = model.x1)
xgb.plot.importance(importance_jf)
各维度最终权重结果如下图:
最终结果大家也可以看到,我复投预测的数据经过同样的活动及短信营销后,转化率为10%,7天后最终转化率超过了20%;
而业务部门做的5月8日的同样活动,也是发送的是新用户人群,转化率为2.5%,7天后最终转化率没有超过5%。

用R做一个完整的数据挖掘项目相关推荐

  1. 如何去实践一个完整的数据挖掘项目?

    [每日一问] 如何去实践一个完整的数据挖掘项目? 机器学习项目 1 抽象成数学问题(明确问题) 2 获取数据 3 特征预处理与特征选择 4 训练模型与调优 5 模型诊断 6 模型融合(非必须) 7 上 ...

  2. 用PaddleDetection做一个完整的目标检测项目(上)

    文章转载自:微信公众号:飞桨PaddlePaddle的微信文章 原文章中由于排版问题,导致文字遮挡,不便阅读,因此对文章格式稍作更改,增加了一些关键词加粗,便于后续阅读. PaddleDetectio ...

  3. 如何使用graphpad做柱形图_系列文章 如何使用PaddleDetection做一个完整项目(三)...

    系列文章 如何使用PaddleDetection做一个完整项目(三) 该文章是PaddleDetection的完结篇,请参考之前两篇文章 https://zhuanlan.zhihu.com/p/10 ...

  4. Scikit-Learn TensorFlow机器学习实用指南(二):一个完整的机器学习项目【上】

    机器学习实用指南(二):一个完整的机器学习项目[上] 作者:LeonG 本文参考自:<Hands-On Machine Learning with Scikit-Learn & Tens ...

  5. 机器学习入门系列(2)--如何构建一个完整的机器学习项目(一)

    上一篇机器学习入门系列(1)–机器学习概览简单介绍了机器学习的一些基本概念,包括定义.优缺点.机器学习任务的划分等等. 接下来计划通过几篇文章来介绍下,一个完整的机器学习项目的实现步骤会分为几步,最后 ...

  6. 做一个成功的软件项目经理

    做一个成功的软件项目经理 概述 要想做一个成功的软件项目经理需要有丰富的管理知识,同时要有全面的技术知识. 同时在知识的结合下在实际中应用管理学的计划,组织,控制,激励,领导等职能,发挥个人管理的长处 ...

  7. 【React进阶-1】从0搭建一个完整的React项目(入门篇)

    这篇文章带领大家从零开始手动撸一个React项目的基础框架,集成React全家桶.万字长文,请各位有足够的时间时再来阅读和学习. 概述 平时工作中一直在用React提供的脚手架工具搭建React项目, ...

  8. react全家桶从0搭建一个完整的react项目(react-router4、redux、redux-saga)

    react全家桶从0到1(最新) 本文从零开始,逐步讲解如何用react全家桶搭建一个完整的react项目.文中针对react.webpack.babel.react-route.redux.redu ...

  9. 如何做一个优秀的数据分析项目?

    上一篇我们普及了[数据分析项目,是什么?为什么我没做过?].今天我们系统讲解一下:如何做一个优秀的数据分析项目.首先大家要明白,并不是所有的项目,都需要找一个万人大会堂,拉着横幅,董事长总经理轮流上台 ...

最新文章

  1. MySQL/MariaDB基础及简单SQL语句
  2. 小程序调用微信支付返回错误
  3. WPF 开发前学习(一)
  4. windows进程间通信方式总结
  5. java 文件通配符_Java中泛型通配符的使用方法示例
  6. java命令模式返回值_JAVA 设计模式 命令模式
  7. DefenseCode ThunderScan 静态代码审计工具
  8. 【java学习之路】(java SE篇)(讨论与思考)异常中的try,catch,return的相关问题
  9. python 字节字符串_Python字符串转换为字节,字节转换为字符串
  10. 安卓版App开发心得
  11. velocity--shiro
  12. windows自带黑体_Windows自带的宋体、黑体、楷体、仿宋体等能免费商用吗?
  13. 电影中的计算机 过去与未来
  14. 基于java高德地图经纬度转详细地址和GPS坐标转换为高德地图坐标
  15. Event-Driven架构设计消息处理系统
  16. 【转换输出流小练习 】现有一字符串:”我爱Java”。将该字符串保存到当前项目根目录下的a.txt文件中。​
  17. 关闭计算机休眠文件,电脑垃圾清理关闭休眠文件夹hiberfil.sys
  18. ubuntu 16.04 编译android 7.1,jack报错
  19. 计算机考试打字题遇到字母怎么办,手把手为你解决win10系统打字时莫名其妙出现字母的解决方法...
  20. datafountain自然语言处理比赛的学习和总结

热门文章

  1. 佛祖在钉钉 - 工作中的六波罗蜜
  2. 超级好用的代码阅读器source insight破解版安装和使用
  3. html5手机网站照片查看器,pc端、移动端照片查看器(照片编辑器插件)
  4. npoi ppt html,NPOI(示例代码)
  5. php7 一句话木马,PHP一句话木马及查杀
  6. 服务器修改拔刀剑修改数,关于拔刀剑的(求助大佬!)
  7. DZ先生怪谈国标28181之浅显易懂的国标编码
  8. 子桓说:什么样的员工不怕被裁员?
  9. Thinkphp5.1+workerman+getway实现聊天功能
  10. ResultSetMetaData的用法介绍