企业级用户画像:开发RFM模型实例
絮叨两句:
博主是一名数据分析实习生,利用博客记录自己所学的知识,也希望能帮助到正在学习的同学们
人的一生中会遇到各种各样的困难和折磨,逃避是解决不了问题的,唯有以乐观的精神去迎接生活的挑战
少年易老学难成,一寸光阴不可轻。
最喜欢的一句话:今日事,今日毕
本篇文章为大家分享如何开发RFM模型实例,之前文章有介绍过什么是RFM,具体了解请点击:使用大数据去挖掘每个用户的客户价值-RFM
开发RFM使用的是K-Means算法,K-Means算法入门案例:
如何了解K-Means聚类算法?[内含鸢尾花案例]
企业级360°全方位用户画像:标签开发(前期准备工作)
需求分析
用户的客户价值肯定是有等级的:
- 超高价值
- 高价值
- 中上价值
- 中价值
- 中下价值
- 低价值
- 超低价值
客户价值标签规则:inType=HBase##zkHosts=192.168.10.20##zkPort=2181##hbaseTable=tbl_orders##family=detail##selectFields=memberId,orderSn,orderAmount,finishTime
代码
package cn.itcast.userprofile.up24.newexcavateimport cn.itcast.userprofile.up24.public.PublicStaticCode
import org.apache.spark.ml.clustering.KMeans
import org.apache.spark.ml.feature.{MinMaxScaler, VectorAssembler}
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession}import scala.collection.immutableobject RFM extends PublicStaticCode{override def SetAppName: String = "RFM"override def Four_Name: String = "客户价值"override def compilerAdapterFactory(spark: SparkSession, five: DataFrame, tblUser: DataFrame): DataFrame = {/*** +------+----+* |tagsId|rule|* +------+----+* |38 |1 |* |39 |2 |* |40 |3 |* |41 |4 |* |42 |5 |* |43 |6 |* |44 |7 |* +------+----+*/
// five.show(false)/*** orderSn 订单号* orderAmount 订单总金额,等于商品总金额+运费* finishTime 订单完成时间* +---------+-------------------+-----------+----------+* |memberId |orderSn |orderAmount|finishTime|* +---------+-------------------+-----------+----------+* |13823431 |ts_792756751164275 |2479.45 |1564415022|* |4035167 |D14090106121770839 |2449.00 |1565687310|* |4035291 |D14090112394810659 |1099.42 |1564681801|* |4035041 |fx_787749561729045 |1999.00 |1565799378|* |13823285 |D14092120154435903 |2488.00 |1565062072|*/
// tblUser.show(false)/*** Desc 客户价值模型-RFM:* R值:最近一次消费(Recency) 最近一次消费,最后一次订单距今时间* F值:消费频率(Frequency) 消费频率,订单总数量* M值:消费金额(Monetary) 消费金额,订单总金额**/import spark.implicits._import scala.collection.JavaConversions._import org.apache.spark.sql.functions._//0.定义常量字符串,避免后续拼写错误val recencyStr = "recency"val frequencyStr = "frequency"val monetaryStr = "monetary"val featureStr = "feature"val predictStr = "predict"//1.按用户id进行聚合获取客户RFM//客户价值模型-RFM://Rencency:最近一次消费,最后一次订单距今时间//Frequency:消费频率,订单总数量//Monetary:消费金额,订单总金额/*** datediff(end: Column, start: Column) 两日期间隔天数 date_sub(start: Column, days: Int) 指定日期之前n天* from_unixtime(ut: Column, f: String) 时间戳转字符串格式*///date_sub(current_timestamp(),361) 为什么要这样写! HBase里存储的数据已经很长时间了var recencyAggColumn=datediff(date_sub(current_timestamp(),361),from_unixtime(max("finishTime"))) as recencyStrvar frequencyAggColumn=count("orderSn") as frequencyStrvar monetaryAggColum=sum("orderAmount") as monetaryStrval rfm_Result: DataFrame = tblUser.groupBy("memberId").agg(recencyAggColumn, frequencyAggColumn, monetaryAggColum)
// rfm_Result.show(false)/*** +---------+-------+---------+------------------+* |memberId |recency|frequency|monetary |* +---------+-------+---------+------------------+* |13822725 |61 |116 |179298.34 |* |13823083 |61 |132 |233524.17 |* |138230919|61 |125 |240061.56999999998|* |13823681 |61 |108 |169746.1 |* |4033473 |61 |142 |251930.92 |* |13822841 |61 |113 |205931.91 |* |13823153 |61 |133 |250698.57 |*///2.为RFM打分//R: 1-3天=5分,4-6天=4分,7-9天=3分,10-15天=2分,大于16天=1分//F: ≥200=5分,150-199=4分,100-149=3分,50-99=2分,1-49=1分//M: ≥20w=5分,10-19w=4分,5-9w=3分,1-4w=2分,<1w=1分var recencyScore=when((col(recencyStr) >= 1) && (col(recencyStr) <= 3), 5).when((col(recencyStr)>=4) && (col(recencyStr)<=6),4).when((col(recencyStr)>=7) && (col(recencyStr)<=9),3).when((col(recencyStr)>=10) && (col(recencyStr)<=15),2).when(col(recencyStr)>16 ,1).as(recencyStr)val frequencyScore = when(col(frequencyStr) >= 200, 5).when((col(frequencyStr) >= 150) && (col(frequencyStr) <= 199), 4).when((col(frequencyStr) >= 100) && (col(frequencyStr) <= 149), 3).when((col(frequencyStr) >= 50) && (col(frequencyStr) <= 99), 2).when((col(frequencyStr) >= 1) && (col(frequencyStr) <= 49), 1).as(frequencyStr)val monetaryScore = when(col(monetaryStr) >= 200000, 5).when(col(monetaryStr).between(100000, 199999), 4).when(col(monetaryStr).between(50000, 99999), 3).when(col(monetaryStr).between(10000, 49999), 2).when(col(monetaryStr) <= 9999, 1).as(monetaryStr)val rfm_Socre: DataFrame = rfm_Result.select('memberId, recencyScore, frequencyScore, monetaryScore)// rfm_Socre.show(10,false)/*** +---------+-------+---------+--------+* |memberId |recency|frequency|monetary|* +---------+-------+---------+--------+* |13822725 |1 |3 |4 |* |13823083 |1 |3 |5 |* |138230919|1 |3 |5 |* |13823681 |1 |3 |4 |* |4033473 |1 |3 |5 |* |13822841 |1 |3 |5 |* |13823153 |1 |3 |5 |* |13823431 |1 |3 |4 |* |4033348 |1 |3 |5 |* |4033483 |1 |3 |4 |* +---------+-------+---------+--------+*///3.聚类//为方便后续模型进行特征输入,需要部分列的数据转换为特征向量,并统一命名,VectorAssembler类就可以完成这一任务。//VectorAssembler是一个transformer,将多列数据转化为单列的向量列val vectorAss: DataFrame = new VectorAssembler().setInputCols(Array(recencyStr, frequencyStr, monetaryStr)).setOutputCol(featureStr).transform(rfm_Socre)
// vectorAss.show()/*** +---------+-------+---------+--------+-------------+* | memberId|recency|frequency|monetary| feature|* +---------+-------+---------+--------+-------------+* | 13822725| 1| 3| 4|[1.0,3.0,4.0]|* | 13823083| 1| 3| 5|[1.0,3.0,5.0]|* |138230919| 1| 3| 5|[1.0,3.0,5.0]|* | 13823681| 1| 3| 4|[1.0,3.0,4.0]|* | 4033473| 1| 3| 5|[1.0,3.0,5.0]|* | 13822841| 1| 3| 5|[1.0,3.0,5.0]|* | 13823153| 1| 3| 5|[1.0,3.0,5.0]|* | 13823431| 1| 3| 4|[1.0,3.0,4.0]|*//*** 数据归一化* 把数据映射到0-1范围之内,更加便捷快速* 可以使用,也可以不用*/val minMaxScalerModel = new MinMaxScaler().setInputCol(featureStr).setOutputCol(featureStr + "Out").fit(vectorAss)val scalerDF = minMaxScalerModel.transform(vectorAss)
// scalerDF.show()/*** +---------+-------+---------+--------+-------------+--------------+* | memberId|recency|frequency|monetary| feature| featureOut|* +---------+-------+---------+--------+-------------+--------------+* | 13822725| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 13823083| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* |138230919| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* | 13823681| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 4033473| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* | 13822841| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* | 13823153| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* | 13823431| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 4033348| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* | 4033483| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 4033575| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* | 4034191| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* | 4034923| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 13823077| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* |138230937| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 4034761| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* | 4035131| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 13822847| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* |138230911| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* | 4034221| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]|* +---------+-------+---------+--------+-------------+--------------+*/val kMeans = new KMeans().setK(7).setSeed(10) //可重复的随机种子.setMaxIter(10) //最大迭代次数.setFeaturesCol(featureStr+"Out") //特征列.setPredictionCol(predictStr) //预测结果列//4.训练模型val model = kMeans.fit(scalerDF)//5.预测val result: DataFrame = model.transform(scalerDF)
// result.show(10)/*** +---------+-------+---------+--------+-------------+--------------+-------+* | memberId|recency|frequency|monetary| feature| featureOut|predict|* +---------+-------+---------+--------+-------------+--------------+-------+* | 13822725| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]| 1|* | 13823083| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]| 0|* |138230919| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]| 0|* | 13823681| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]| 1|* | 4033473| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]| 0|* | 13822841| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]| 0|* | 13823153| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]| 0|* | 13823431| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]| 1|* | 4033348| 1| 3| 5|[1.0,3.0,5.0]| [0.5,0.5,1.0]| 0|* | 4033483| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]| 1|* +---------+-------+---------+--------+-------------+--------------+-------+*///6.测试时看下聚类效果val ds: Dataset[Row] = result.groupBy(predictStr).agg(max(col(recencyStr) + col(frequencyStr) + col(monetaryStr)), min(col(recencyStr) + col(frequencyStr) + col(monetaryStr))).sort(col(predictStr).asc)
// ds.show()/*** +-------+---------------------------------------+---------------------------------------+* |predict|max(((recency + frequency) + monetary))|min(((recency + frequency) + monetary))|* +-------+---------------------------------------+---------------------------------------+* | 0| 9| 9|* | 1| 8| 8|* | 2| 3| 3|* | 3| 7| 7|* | 4| 11| 10|* | 5| 5| 4|* | 6| 8| 7|* +-------+---------------------------------------+---------------------------------------+*///问题: 每一个簇的ID是无序的,但是我们将分类簇和rule进行对应的时候,需要有序//7.按质心排序,质心大,该类用户价值大//[(质心id, 质心值)]val centers: immutable.Seq[(Int, Double)] = for (i <- model.clusterCenters.indices) yield (i, model.clusterCenters(i).toArray.sum)val sortedCenter: immutable.Seq[(Int, Double)] = centers.sortBy(_._2).reverse
// sortedCenter.foreach(println)/*** (4,2.2596153846153846)* (0,2.0)* (1,1.75)* (6,1.625)* (3,1.5)* (5,0.8333333333333333)* (2,0.5)*///[(质心id, rule值)]val centerIdAndRule = for (i <- sortedCenter.indices) yield (sortedCenter(i)._1, i + 1)
// centerIdAndRule.foreach(println)/*** (4,1)* (0,2)* (1,3)* (6,4)* (3,5)* (5,6)* (2,7)*/val centerDf: DataFrame = centerIdAndRule.toDF(predictStr, "rule")
// centerDf.show()/*** +-------+----+* |predict|rule|* +-------+----+* | 4| 1|* | 0| 2|* | 1| 3|* | 6| 4|* | 3| 5|* | 5| 6|* | 2| 7|* +-------+----+*//*** 将预测的结果和五级标签进行匹配*/val ruleTag: DataFrame = centerDf.join(five, "rule")// result.show()/*** +----+-------+------+* |rule|predict|tagsId|* +----+-------+------+* | 1| 4| 38|* | 2| 0| 39|* | 3| 1| 40|* | 4| 6| 41|* | 5| 3| 42|* | 6| 5| 43|* | 7| 2| 44|* +----+-------+------+*/val perdict: DataFrame = ruleTag.select(predictStr, "tagsId")// 方法一:直接与K-Means计算出的结果进行Join
// var new_tag= perdict.join(result,predictStr)//new_tag.show()/*** +-------+------+---------+-------+---------+--------+-------------+--------------+* |predict|tagsId| memberId|recency|frequency|monetary| feature| featureOut|* +-------+------+---------+-------+---------+--------+-------------+--------------+* | 1| 40| 13822725| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 13823681| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 13823431| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 4033483| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 4034923| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40|138230937| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 4035131| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 4034603| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40|138230903| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 4035125| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 4035101| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 4033585| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 13823023| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 4034927| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 13823069| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 4034205| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 4035183| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 69| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 13823439| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* | 1| 40| 13823085| 1| 3| 4|[1.0,3.0,4.0]|[0.5,0.5,0.75]|* +-------+------+---------+-------+---------+--------+-------------+--------------+*///方法二:val perMap = perdict.map(t => {val pre = t.getAs(predictStr).toStringval tag = t.getAs("tagsId").toString(pre, tag)}).collect().toMapprintln(perMap)//Map(4 -> 38, 5 -> 43, 6 -> 41, 1 -> 40, 0 -> 39, 2 -> 44, 3 -> 42)var predictUdf=udf((perdict:String)=>{var tag=perMap(perdict)tag})val new_Tag = result.select('memberId as "userId", predictUdf('predict) as "tagsId")new_Tag.show()/*** +---------+------+* | memberId|tagsId|* +---------+------+* | 13822725| 40|* | 13823083| 39|* |138230919| 39|* | 13823681| 40|* | 4033473| 39|* | 13822841| 39|* | 13823153| 39|* | 13823431| 40|* | 4033348| 39|* | 4033483| 40|* | 4033575| 39|* | 4034191| 39|* | 4034923| 40|* | 13823077| 39|* |138230937| 40|* | 4034761| 39|* | 4035131| 40|* | 13822847| 39|* |138230911| 39|* | 4034221| 39|* +---------+------+*/new_Tag}def main(args: Array[String]): Unit = {startMain()}
}
以上就是RFM模型实例的开发
若有什么正确的地方还请及时反馈,博主及时更正
如能帮助到你,希望能点个赞支持一下谢谢!
企业级用户画像:开发RFM模型实例相关推荐
- 企业级用户画像:基于USG模型使用决策树开发用户购物性别
絮叨两句: 博主是一名数据分析实习生,利用博客记录自己所学的知识,也希望能帮助到正在学习的同学们 人的一生中会遇到各种各样的困难和折磨,逃避是解决不了问题的,唯有以乐观的精神去迎接生活的挑战 少年易老 ...
- python数据分析实战之用户分析及RFM模型分析
理论基础知识可以看我之前的博客: 1.python之Numpy知识点详细总结 2.python最最最重要的数据分析工具之pandas 3.pandas之表连接与高级查询 也可以进入我的专栏:欢迎订阅哦 ...
- 大数据项目实战教程:使用SparkSQL+Hbase+Oozie构建企业级用户画像
大数据项目实战教程,本课程需要有大数据基础(掌握基本大数据组件应用)的人才可以学习哦!市面上全面的大数据教程较少,今天分享给大家的就是一套全面的大数据学习教程,企业级大数据项目:360度用户画像实战 ...
- SparkSQL电商用户画像(五)之用户画像开发(客户基本属性表)
7.1用户画像–数据开发的步骤 u 数据开发前置依赖 -需求确定 pv uv topn -建模确定表结构 create table t1(pv int,uv int,topn string) -实现方 ...
- 用户分析与RFM模型实战|一个可以写在简历上的项目(下)
大家好,我是芒果. 接上文:用户分析与RFM模型实战|一个可以写在简历上的项目(上) 本篇会继续对此数据对产品维度和用户分层维度进行分析. 依然结论先行: 重要结论
- 用户行为分析模型——RFM模型
用户行为分析模型--RFM模型 1. RFM模型 2. RFM模型分析应用 1. RFM模型 RFM模型根据客户活跃程度和交易金额的贡献,进行客户价值细分的一种方法. R(Recency)--最近一次 ...
- 企业级用户画像: 用户活跃度模型-RFE
絮叨两句: 博主是一名数据分析实习生,利用博客记录自己所学的知识,也希望能帮助到正在学习的同学们 人的一生中会遇到各种各样的困难和折磨,逃避是解决不了问题的,唯有以乐观的精神去迎接生活的挑战 少年易老 ...
- 企业级用户画像:用户购物性别模型-USG和决策树算法
絮叨两句: 博主是一名数据分析实习生,利用博客记录自己所学的知识,也希望能帮助到正在学习的同学们 人的一生中会遇到各种各样的困难和折磨,逃避是解决不了问题的,唯有以乐观的精神去迎接生活的挑战 少年易老 ...
- 除征信快查外,用户画像和风控模型如何助力网络小贷风控
对于网络小贷平台而言,征信和风控是业务发展过程中的重要环节.网络小贷业务主要防范的是欺诈风险和信用风险,诸如借款人通过套现.伪造.冒领冒用.恶意透支等手段进行骗贷.此外,平台与平台之间信息不透明,用户 ...
最新文章
- 宋祖儿面对粉丝不停撩头发,手上的书本亮了,是要转行当程序员?
- 【坑爹微信】微信JSSDK图片上传问题和解决
- 让线程等待10秒_把python程序变成多线程
- kafka metric java,jmx_exporter+prometheus+grafana实现kafka metric监控
- C++设计模式之四 模板模式
- Solaris 图形化界面登陆的控制
- c# checkbox 外观_2020款日产蓝鸟上市!外观比大众朗逸漂亮,油耗6L 国六,9.59万_搜狐汽车...
- css line-height多种用法与之间的区别
- matlab 循环和判断语句,matlab中循环语句与for循环
- 纪念 | 永远的凌晨四点钟
- Mybatis XML文件属性配置
- 【海洋科学】高精度地形数据画出的水深图
- 贴片电解电容47UF16V 6.3*4.5
- 博士申请 | 卡耐基梅隆大学陈贝迪老师课题组招收机器学习方向博士生
- 笔记本连接WiFi后浏览器不能上网,但是连接手机热点就可以。问题解决!!!
- EM算法双硬币模型的python实现
- python股票成交明细_Python股票成交价格-买卖额分布图(三)
- html标签做代码块
- JS与DOM的兼容性
- R-EACTR:一个设计现实网络战演习的框架
热门文章
- 上海亚商投顾:沪指失守3300点 传媒、游戏板块逆市大涨
- 在XP上同时运行IE6,IE7,IE8,IE9
- PHP实现微信的时间显示方式
- 陈艾盐:《春燕》百集访谈节目第五十九集
- 抖音橱窗等级被降低了是什么原因造成的?怎么办?
- 云集宣布品牌升级,推出全新slogan“购物享受批发价”
- 2018年度10大新兴技术:人工智能、量子计算、增强现实等
- 个人总结:京东技术体系员工级别划分及薪资区间
- 知道了蚂蚁森林这个“秘密”,我坐不住了!!
- 戴尔硬件服务器,服务器硬件、结构介绍_Intel Xeon E5-2660 v4_服务器x86服务器-中关村在线...