精华内容
下载资源
问答
  • 企业级用户画像:开发RFM模型实例

    千次阅读 2020-10-12 17:18:31
    本篇文章为大家分享如何开发RFM模型实例,之前文章有介绍过什么是RFM,具体了解请点击:使用大数据去挖掘每个用户的客户价值-RFM 开发RFM使用的是K-Means算法,K-Means算法入门案例:如何了解K-Means聚类算法?[内含鸢尾花...

    絮叨两句:
    博主是一名数据分析实习生,利用博客记录自己所学的知识,也希望能帮助到正在学习的同学们
    人的一生中会遇到各种各样的困难和折磨,逃避是解决不了问题的,唯有以乐观的精神去迎接生活的挑战
    少年易老学难成,一寸光阴不可轻。
    最喜欢的一句话:今日事,今日毕

    本篇文章为大家分享如何开发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.newexcavate
    
    import 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.immutable
    
    object 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 recencyStr
        var frequencyAggColumn=count("orderSn") as frequencyStr
        var monetaryAggColum=sum("orderAmount") as monetaryStr
    
        val 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).toString
          val tag = t.getAs("tagsId").toString
          (pre, tag)
        }).collect().toMap
        println(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模型是一个被广泛使用的客户关系分析模型,主要以用户行为来区分客户。通过RFM模型,为用户分群,实现精细化运营。
  • 主要介绍了Python pandas RFM模型应用,结合实例形式详细分析了pandas RFM模型的概念、原理、应用及相关操作注意事项,需要的朋友可以参考下
  • RFM模型以及案例

    千次阅读 2019-08-08 15:31:39
    一.RFM模型定义 百度百科定义: **RFM模型是衡量客户价值和客户创利能力的重要工具和手段。在众多的客户关系管理(CRM)的分析模式中,RFM模型是被广泛提到的。该机械模型通过一个客户的近期购买行为、购买的总体频率...

    一.RFM模型定义

    	百度百科定义:
    	**RFM模型是衡量客户价值和客户创利能力的重要工具和手段。在众多的客户关系管理(CRM)的分析模式中,RFM模型是被广泛提到的。该机械模型通过一个客户的近期购买行为、购买的总体频率以及花了多少钱3项指标来描述该客户的价值状况.* *
    

    简单来说就是通过最近一次消费(recency),消费频率(frequency),消费金额(monetary)来判断这个用户的价值.

    二.案例

    1.使用的表格

    在这里插入图片描述
    每一列分别是订单id,顾客id,时间,金额,类型,类型(英文)
    在这里插入图片描述
    2.处理时间,使用时间戳
    在这里插入图片描述
    在这里插入图片描述
    3.按照顾客id和类型分组
    在这里插入图片描述
    4.R
    在这里插入图片描述
    先创建透视表,再把最近一次消费时间添加为’最近时间’
    在这里插入图片描述
    5.F
    在这里插入图片描述
    透视表:
    在这里插入图片描述
    填充nan值为0:
    在这里插入图片描述
    将退货变为负值:
    在这里插入图片描述
    汇总:
    在这里插入图片描述
    6. M

    在这里插入图片描述
    创建透视表
    在这里插入图片描述
    把nan值填充为0
    在这里插入图片描述
    汇总:
    在这里插入图片描述
    7.将需要的3列合并
    在这里插入图片描述
    8.根据数据使用cut()给客户评级
    在这里插入图片描述

    展开全文
  • 而其中最经典的当属RFM模型吧,简单好操作而且还十分实用,下面就介绍一些怎么构建RFM模型。 一、什么是RFM模型? R是指用户的最近一次消费时间,用最通俗的话说就是,用户最后一次下单时间距今天有多长时间了,这...

    如何让数据分析来帮助业务挣钱,这是每个数据分析师都会考虑的问题,近几年经常提到的精细化运营、数据驱动增长、增长黑客这样的字眼,这背后的核心就是用户行为分析。

    而其中最经典的当属RFM模型吧,简单好操作而且还十分实用,下面就介绍一些怎么构建RFM模型。

    一、什么是RFM模型?

    R是指用户的最近一次消费时间,用最通俗的话说就是,用户最后一次下单时间距今天有多长时间了,这个指标与用户流失和复购直接相关。

    F是指用户下单频率,通俗一点儿就是,用户在固定的时间段内消费了几次。这个指标反映了用户的消费活跃度。

    M是指用户消费金额,其实就是用户在固定的周期内在平台上花了多少钱,直接反映了用户对公司贡献的价值。

    而RFM模型就是通过一个客户的近期购买行为、购买的总体频率以及花了多少钱三项指标,来描述该客户的价值状况。

    二、RFM模型有什么作用?

    RFM模型可以对客户的终生价值做一个合理的预估,基于一个理想的客户特征来衡量现实中客户价值的高低,通过此类分析,定位最有可能成为品牌忠诚客户的群体,让我们把主要精力放在最有价值的用户身上。

    三、怎么构建RFM模型?

    下面我们就直接开始进行实操教程,以某家零售商的销售数据为数据源,针对其用户行为简单分析一下,总结来说有下面几个步骤:
     

    1、人群划分

    进行客户行为分析的第一步是按照企业实际业务需求对您的客户群进行分类,人群细分参考的属性主要分为三大类:

    • 基础属性:如性别、年龄、地域
    • 兴趣属性:如媒体偏好、交易行为
    • 自定义属性:基于行业的特征定义的属性,比如乳业需要知道这个人有没有孩子

    2、明确指标

    也就是通过excel或者BI工具计算出每个客户的RFM指标,这里我用的是FineBI,通过客户名称、消费时间、消费金额来处理出上次交易间隔R、交易频率F、交易金额M三个原始字段,如下图所示。

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    但是要注意的是这三个指标不是死板不变的,要针对自己的行业特点灵活变通,比如在金融行业,最近一次购买时间可能并不适用,此时可以考虑采用金融产品持有时间来代替R,这样更能体现用户与金融企业建立联系时间的长短。

    而我们这次要使用的数据指标有四个,分别为“订单额”、“订单量”、“下单时间”和“客户方”,其他指标如“订单类型”、“地区”等我们暂时先不用。

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    3、数据连接

    finebi中设置了很多的数据连接方式,可以通过oracle等数据库进行连接、sql连接等等,这里我直接导入的Excel表,能方便地处理非及时性数据。

    如果我们有多个数据源的数据,需要分别选择不同的指标整合到一起分析怎么办?

    这里我发现finebi有个非常人性化的优点,就是可以通过自助数据集的方式对数据指标进行整合,如下图所示直接选择新建自助数据集—选择数据表—添加字段即可,需要什么指标就去哪张表里去找,很方便。

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    4、数据清洗

    在进行数据分析之前,我们首先要做的就是对数据进行初步加工,因为数据源中很多脏数据,会影响我们的分析结果,需要先将其筛选出去,比如一些空值、异常值、特殊文本显示等等。

    finebi的数据加工中包含了很多处理功能,比如过滤、分组汇总、排序、合并、聚合等等,这些功能我们后面都会用到,这里我们先增加两个过滤条件,将订单金额小于等于零、且订单时间为空的数据筛选出去。

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    我们通过上面的数据表可以看出,同一个客户如果下单两次,就会产生两个数据,而RFM模型中要求的数据是“最近一次下单时间”、“最近一段时间内的下单次数”以及“最近一段时间内的购买金额”,因此我们要想办法计算用户行为次数。

    具体方法是新增一列,命名为“次数”,数值设为常数1,主要目的是为了后面方便计算个数,同一个客户出现了多少次数值1,就说明下单了几次;

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    然后我们选择“分组汇总”,以“客户名”为主要汇总项,“次数”项选择加和汇总,代表某个客户出现了几次;同时将“订单时间”设置为“最晚时间”,也就是距离今天最近的一次消费时间,这样基本的数据清洗就完成了。

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    但是因为还要计算客户最近一次购买有多远,而数据表中仅仅是下单时间,所以需要用函数计算一下下单时间与今天的天数,但finebi不用那么麻烦,可以直接计算时间差:

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    5、切分指标

    因为我们要把用户按照三个维度指标进行划分,也就相当于将用户放到下面这个正方体中:

     

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    因此我们要对指标进行切分,设定阈值,也就是为指标设定正负值,确保三个指标将用户分为八个象限。通常比较常用的方法就是等频和等宽进行切分,比如将用户购买花费进行平均值计算。

    但是平均值只适合于均类数据,对于一些不规则数据,平均值会造成很大的误差:

    比如一家公司有三家客户,订单额分别为1万、5千和1百,显然重要客户应该是前两个。而三个客户的订单平均值为5033,如果按照平均值划分数据,那么只有第一个客户符合重要客户的标准,这显然是不对的。

    这时候我们就要用到聚合的功能,简单说,聚合功能就是一堆数据按照内在特征的不同进行划分,不同类的数据之间的差别一般是很大的,这样就能找到大数据量中的“中心点”,而非平均点。

    在FineBI中我们可以直接使用聚合功能,聚合指标选择“订单金额“、”时间“、”次数“,聚合数选择”3“,聚合方式选择”欧氏距离“,这样就可以得到最终的聚合结果了,最终可以计算出每个客户的聚合R值、聚合F值和聚合M值,这就是我们要用到的参考值。

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    有了参考值,下一步就是将时间、频次与订单额与参考值进行比较,这里我们会用到finebi中的逻辑函数IF,新建一列为R,具体函数为:

    • IF(时间<时间中心点,1,0)

    其含义为如果时间列中的数据大于聚合之后的时间中心点,如果小于聚合R值,则为1,反之则为0;

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    同理对其他两个指标也进行划分,这样指标细分工作基本上就完成了。

     

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

     

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    6、用户分类

    我们将三个指标分别进行划分后,按照下图的方式进行组合,就可以得到八个象限,代表8类客户:

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    在finebi中我们先新增一列为RFM值,为了方便分组,我们的计算公式为R*100+F*10+M,也就能得出0、1、10、11、100、101、110、111八个不同的值,分别代表八种客户类型。

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    这样我们的用户细分也就完成了。

    7、可视化分析

    利用FineBI对客户进行细分,可以将其制作成可视化数据分析模板,以便我们按照需求进行客户分析。

    最详细的RFM模型实操案例!让用户行为分析事半功倍

     

    • 例如图中的面积图,可以显示出该公司各类客户的占比,显而易见一般挽留客户与一般发展客户占据多数,说明该公司的用户结构不是很合理,需要尽快采取措施进行优化;
    • 而右侧的环形图则代表着各种类型客户的购买数量,可以看出复购率越高、愿意花大价钱的客户买的数量越多;
    • 左侧的仪表盘代表着某种类型客户的数量,而下方的详细图则详细展示了某家客户的类型和对应的R、F、M值。

    总结

    其实RFM在用户行为分析中的应用十分广泛,因为时间原因这里就只是做一个简单的教程,FineBI中也有更多的相关数据可供大家练习!

    注:finebi下载链接,可以后台私信回复我“数据分析”获得!

    展开全文
  • 数据挖掘应用案例 RFM 模型分析与客户细分 分类 数据挖掘 | 标签 市场研究 数据挖掘 RFM 模型 2012-01-21 21:39 阅读 ( 16854 ) 评论 (9) 这里我先给各位朋友 拜年祝大家新春快乐 兔年就要过去了本命年的最后一天...
  • 这篇文章主要介绍了Python pandas RFM模型应用,结合实例形式详细分析了pandas RFM模型的概念、原理、应用及相关操作注意事项,需要的朋友可以参考下 文章目录什么是RFM模型RFM实践应用1、前提假设验证2、RFM分级4、...

    这篇文章主要介绍了Python pandas RFM模型应用,结合实例形式详细分析了pandas RFM模型的概念、原理、应用及相关操作注意事项,需要的朋友可以参考下


    本文实例讲述了Python pandas RFM模型应用。分享给大家供大家参考,具体如下:

    什么是RFM模型

    根据美国数据库营销研究所Arthur Hughes的研究,客户数据库中有3个神奇的要素,这3个要素构成了数据分析最好的指标:

    最近一次消费 (Recency): 客户最近一次交易时间的间隔。R值越大,表示客户交易距今越久,反之则越近;
    消费频率 (Frequency): 客户在最近一段时间内交易的次数。F值越大,表示客户交易越频繁,反之则不够活跃;
    消费金额 (Monetary): 客户在最近一段时间内交易的金额。M值越大,表示客户价值越高,反之则越低

    RFM实践应用

    1、前提假设验证

    RFM模型的应用是有前提假设的,即R、F、M值越大价值越大,客户未来的为企业带来的价值越大。这个前提假

    设其实已经经过大量的研究和实证,假设是成立的。不过为了更加严谨,确保RFM模型对于特殊案例是有效的,

    本文还进行了前提假设验证:

    ps:Frequency、Monetary均为近6个月内的数据,即1-6月数据;

    利用相关性检验,验证假设:

    最近购买产品的用户更容易产生下一次消费行为
    消费频次高的用户,用户满意度高,忠诚度高,更容易产生下一次消费行为
    消费金额高的用户更容易带来高消费行为

    2、RFM分级

    简单的做法,RFM三个指标以均值来划分,高于均值的为高价值、低于均值的为低价值,如此可以将客户划分为8大类:在这里插入图片描述
    本文采取的方法是将三个指标进行标准化,然后按照分为数划分为5个等级,数值越大代表价值越高;当然最终划分的规则还是要结合业务来定。划分为5个等级后,客户可以细分为125种。

    #读取数据
    rfm<-read.csv('~/desktop/rfm1_7.csv',header=TRUE)
    summary(rfm)
    #数据分布
    par(mfrow=c(1,3))
    boxplot(rfm$rankR1) 
    boxplot(rfm$rankF1) 
    boxplot(rfm$rankM1)
    #rfm分级
    breaks1<-quantile(rfm$Recency, probs = seq(0, 1, 0.2),names = FALSE)
    breaks1<-c(1,14,30,57,111,181) #以流失用户的定义来设置分级 30天以上为流失用户
    breaks2<-quantile(rfm$Frequency, probs = seq(0, 1, 0.2),names = FALSE)
    breaks2<-c(1,2,3,6,14,164) 
    breaks3<-quantile(rfm$Monetary, probs = seq(0, 1, 0.2),names = FALSE)
    rfm$rankR1<- cut(rfm$Recency,breaks1, 5,labels=F)
    rfm$rankR1<- 6-rfm$rankR1
    rfm$rankF1<- cut(rfm$Frequency,breaks2, 5,labels=F)
    rfm$rankM1<- cut(rfm$Monetary,breaks3, 5,labels=F)
    

    3、客户分类
    本文采用K-means聚类进行分类,聚类结果结合业务划分为4大类:

    Cluster1:价值用户R、F、M三项指标均较高;
    Cluster2,3:用户贡献值最低,且用户近度(小于2)和频度较低,为无价值客户;
    Cluster4:发展用户,用户频度和值度较低,但用户近度较高,可做up营销;
    Cluster5:挽留客户,用户近度较低,但频度和值度较高,需采用挽留手段
    k值选择:在这里插入图片描述
    聚类结果:在这里插入图片描述

    #聚类
    df<-rfm[,c(6,7,8)]
    p1<-fviz_nbclust(df, kmeans, method = "wss")
    p2<-p1 + geom_vline(xintercept = 5, linetype = 2)
    km_result <- kmeans(df, 5)
    dd <- cbind(rfm,df, cluster = km_result$cluster)
    ##查看每一类的数目
    table(dd$cluster)
    picture<-fviz_cluster(km_result, df, geom = "point")
    ####聚类结果解释####
    rfm_final <- within(dd,{Custom = NA
    Custom[cluster == 1] = '高价值客户'
    Custom[cluster == 2 ] = '无价值客户'
    Custom[ cluster == 3] = '无价值客户'
    Custom[cluster == 4] = '重点发展客户' 
    Custom[cluster == 5] = '重点挽留客户'
    })
    

    4、RFM打分

    步骤3,我们将客户划分为四大类,其实如果一类客户中还有大量的客户,此时为了精细化营销,可以根据RFM进行加权打分,给出一个综合价值的分。这里,运用AHP层次分析法确定RFM各指标权重:

    客户价值RFM_SCORE= 0.25rankR + 0.20rankF+0.55*rankM

    AHP层次分析法(专家打分法)在这里插入图片描述
    总结
    上述客户分类其实比较粗旷,真正在面对千万级客户量时,如此划分为四大类是难以满足运营需求的。运营中,还需要综合CRM中其他指标、维度。

    ps:后续作者利用RFM客户价值得分进行潜在客户挖掘,尝试利用决策树等模型挖掘平台潜在客户特征。

    简单实例

    import pandas as pd
    import numpy as np
    import time
    #todo 读取数据
    data = pd.read_csv('RFM_TRAD_FLOW.csv',encoding='gbk')
    # print(ret)
    # todo RFM------>R(最近一次消费)
    #todo 时间与字符串相互转换
    data['time'] = data['time'].map(lambda x:time.mktime(time.strptime(x,'%d%b%y:%H:%M:%S')))
    # print(data)
    # todo 分组
    groupby_obj = data.groupby(['cumid','type'])
    # for name,data in groupby_obj:
    #   print(name)
    #   print(data)
    # todo 取值
    R = groupby_obj[['time']].max()
    # print(
    # todo 转为透视表
    r_trans = pd.pivot_table(R,index='cumid',columns='type',values='time')
    # print(data_trans)
    # todo 替换缺失值 有缺失值,替换成最远的值
    r_trans[['Special_offer','returned_goods']] = r_trans[['Special_offer','returned_goods']].apply(lambda x:x.replace(np.nan,min(x)),axis = 0)
    # print(data_trans)
    r_trans['r_max'] = r_trans.apply(lambda x:sum(x),axis=1)
    # print(r_trans)
    # todo RFM------>F(消费频率)
    # 取值
    F =groupby_obj[['transID']].count()
    # print(F)
    #转为透视表
    f_trans = pd.pivot_table(F,index='cumid',columns='type',values='transID')
    # print(f_trans)
    #替换缺失值
    f_trans[['Special_offer','returned_goods']]= f_trans[['Special_offer','returned_goods']].fillna(0)
    # print(f_trans)
    #
    f_trans['returned_goods'] = f_trans['returned_goods'].map(lambda x:-x)
    # print(f_trans)
    f_trans['f_total'] = f_trans.apply(lambda x:sum(x),axis=1)
    # print(f_trans)
    # todo RFM------>M(消费金额)
    # 取值
    M =groupby_obj[['amount']].sum()
    # print(M)
    #转为透视表
    m_trans = pd.pivot_table(M,index='cumid',columns='type',values='amount')
    # print(f_trans)
    #替换缺失值
    m_trans[['Special_offer','returned_goods']]= m_trans[['Special_offer','returned_goods']].fillna(0)
    # print(f_trans)
    #
    m_trans['m_total'] = m_trans.apply(lambda x:sum(x),axis=1)
    # print(m_trans)
    # 合并
    RFM=pd.concat([r_trans["r_max"],f_trans['f_total'],m_trans['m_total']],axis=1)
    print(RFM)
    r_score = pd.cut(RFM.r_max,3,labels=[0,1,2])
    f_score = pd.cut(RFM.r_max,3,labels=[0,1,2])
    m_score = pd.cut(RFM.r_max,3,labels=[0,1,2])
    

    写到这里,给大家推荐一个资源很全的python学习聚集地,点击进入,这里有资深程序员分享以前学习心得,学习笔记,还有一线企业的工作经验,且给大家精心整理一份python零基础到项目实战的资料,每天给大家讲解python最新的技术,前景,学习需要留言的小细节

    展开全文
  • RFM模型原理详解与实操运用

    千次阅读 2020-07-19 14:33:15
    RFM模型原理详解与实操运用RFM模型原理介绍为什么要使用RFM模型RMF模型原理介绍RFM模型用户细分RFM模型实例操作背景/数据介绍RFM模型异化构建代码实现结果分析 最近在运营课程中学习了RFM模型,又正正好在商务智能的...
  • v1.0 可编辑可修改 一 RFM模型介绍 在营销活动中每个客户的...最流行的莫过于 RFM模型很多实例都表明了这种方法的有效性和便捷性 对于用户价值界定而已 是目前最好的研究手段 而且可以通过主流分析工具 SPSSStatistic
  • Excel搭建RFM模型

    2021-08-21 13:30:52
    1.RFM模型 RFM是3个指标的缩写通;过这3个指标对用户分类的方法称为RFM模型。 最近一次消费时间间隔(Recency) 对于最近一次消费时间间隔(R),上一次消费离得越近(R值越小),用户价值越高,因为最近一 次消费...
  • 深入解读RFM模型-实战应用干货

    千次阅读 2019-10-12 14:20:47
    今天想先谈谈传统企业和电商谈的较多的RFM模型,在众多的客户细分模型中,RFM模型是被广泛提到和使用的。 一、RFM模型概述 RFM模型是网点衡量当前用户价值和客户潜在价值的重要工具和手段。RFM是Rencency(最近一...
  • CRISP-DM:跨行业数据挖掘标准流程 商业理解(Business Understanding) 数据理解(Data ... 构建模型(Modeling) 模型评估(Evaluation) 模型发布(Deployment) Step1:项目背景和业务目标 评估...
  • 认识RFM模型 RFM模型,R-Recency,客户最近一次购买行为的时间,F-Frequency,客户最近一段时间内购买行为的频繁,M-Monetary,客户最近一段时间购买行为的金额。 RFM模型通过这三个方面去衡量客户的价值,可以通过...
  • 正好刚帮某电信行业完成一个数据挖掘工作,其中的RFM模型还是有一定代表性,就再把数据挖掘RFM模型的建模思路细节与大家分享一下吧!手机充值业务是一项主要电信业务形式,客户的充值行为记录正好满足RFM模型的交易...
  • 基于RFM模型的线上零售中的客户细分(一) 简介:RFM模型通常被用来衡量客户价值和客户创利能力,是商业数据分析中的重要工具和手段。这次我将使用RFM模型对线上零售数据进行客户细分。本篇博客是关于客户细分的相关...
  • 传统的用户价值评估模型主要是建立在RFM模型上,通过三个指标:最近消费时间间隔(Recency)、消费频率(Frequency)、消费金额(Monetary),依照各属性“均值”进行分区。但是该方式用明显的缺点: 细
  • 谈到用户分类模型,最被谈及的应该就是RFM模型了。大部分人常把RFM模型挂在嘴边,而在实际使用中的却很难真正的利用起来。这里暂时不去讨论RFM是好是坏。今天的介绍的是另外一个拓展的模型:航空公司客户价值分析...
  • pandas---RFM模型

    2019-08-08 15:08:08
    RFM模型什么是RFM模型RFM实践应用1、前提假设验证2、RFM分级3、客户分类4、RFM打分总结简单实例 什么是RFM模型 根据美国数据库营销研究所Arthur Hughes的研究,客户数据库中有3个神奇的要素,这3个要素构成了数据...
  • RFM模型由三个基础指标组成: R:最近一次消费至今时间 F:一定时间内重复消费频率 M:一定时间内累计消费金额 RFM模型里,三个变量的含义是很具体的: M:消费越多,用户价值越高。 R:离得越远,用户越有流失可能...
  • Kmeans聚类实例④——电商用户质量聚类分析(RFM

    万次阅读 多人点赞 2019-06-15 18:59:38
    有现成的模型的话(如RFM),可以直接按模型的指标,如果没有,先罗列出比较重要的指标 ③ 从数据库用SQL取出数据 ④ 对数据进行清洗,标准化/归一化/正则化 ⑤ 聚类,如果是现成的模型,则直接聚类即可,如果是拟定...
  • RFM模型综合实战 RFM模型是什么鬼: [数据分析][RFM模型]用数据分析用户 https://www.cnblogs.com/landv/p/12654927.html 官方课程:https://bbs.fanruan.com/course-100.html 手打官方内容,以及自己学习心得体会,...
  • 前言 个人认为该模型可以运用到很多场合不单单...在众多的客户关系管理(CRM)的分析模式中,RFM模型是被广泛提到的。该机械模型通过一个客户的近期购买行为、购买的总体频率以及花了多少钱3项指标来描述该客户的价值..
  • tableau--RFM模型构建

    2020-12-10 09:57:49
    RFM计算字段参考
  • 基于RFM模型的线上零售中的客户细分(二) 1.数据集 在下面的分析中,我将使用从UCI机器学习存储库获得的在线零售数据集。数据包含有关在英国注册的非商店在线零售的跨国交易的信息。 # Importing standard ...
  • 说明 使用kmeans 对客户进行简单的分群。 内容 1 数据 使用了和之前客户流失一样的数据,只不过是做客户分群的任务。 2 正则化处理 ...正则化的过程是将每个样本缩放到单位范数(每个样本的范数为1),如果后面要使用...

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 330
精华内容 132
关键字:

rfm模型实例