当前位置:   article > 正文

RFM模型与Kmeans聚类算法的一些认识-RFM篇_rfm kmeans

rfm kmeans

客户价值RFM模型

首先,RFM模型是市场营销中常用的一个模型,它帮助商家了解每个客户的价值。具体来说,RFM模型包含三个指标:

R(Recency):最近一次购买时间。这个指标反映了客户多久之前还在购买你的产品。

F(Frequency):购买频率。这个指标表示客户在过去一段时间内购买了多少次你的产品。

M(Monetary):购买金额。这个指标代表了客户每次购买时花了多少钱。

总结作用:此标签用以划分用户群体(低价值客户、高价值客户等)

KMeans聚类算法

KMeans是一种聚类算法,它的工作原理是:“人以群分,物以类聚”。

想象一下,你有一堆散落的物品,你想要将它们分成几堆。分类的方法有很多种,而KMeans算法会首先随机选择几个点作为“类簇中心点”,然后计算每个物品到这些中心点的距离,并将每个物品分配到离它最近的中心点所在的那一堆。之后,算法会重新计算每一堆的中心点,并重复这个过程,直到所有物品都稳定地分配到了各个堆中。

KMeans算法(K-均值算法):

  1. K:表示将数值聚类为K个类簇Cluster,划分K个类别,K值大于等于2
  2. Mean:平均值

使用聚类算法给用户打标签步骤:

  1. 特征数据提取
  2. 构建聚类KMeans模型
  3. 给用户打标签

KMeans与RFM的关系

首先,RFM模型是衡量用户价值的重要工具和方法,它由三个基础指标组成:最近一次消费(Recency)、消费频率(Frequency)和消费金额(Money)。这三个指标可以组合起来划分出不同类别的用户人群。

然后,KMeans聚类算法是一种常用的无监督学习算法,它可以将数据样本划分为不同的类别。该算法基于数据点之间的相似性度量进行聚类,通过最小化数据点与所属类别中心点之间的距离来实现聚类的目标。

现在,我们可以将客户的RFM数据看作是那堆散落的物品。每个客户都有一个R值、F值和M值,这可以看作是客户在三维空间中的一个点。

在客户价值分析中,可以使用KMeans聚类算法对RFM模型中的三个指标进行聚类,从而将用户划分为不同的价值类别。具体来说,可以将每个用户的RFM值作为数据点,使用KMeans算法将这些数据点划分为k个互不相交的类别。每个类别由一个中心点代表,该中心点是该类别内所有数据点的均值。这样,就可以根据用户所属的类别来判断其价值高低,并为其打上相应的RFM标签。

因此,KMeans聚类算法在客户价值RFM标签的生成中发挥了重要作用,使得我们可以更加准确地评估用户的价值并为其提供个性化的服务。

通俗解释两者关系

想象一下你是一家电商公司的市场经理。你手上有所有客户的购买数据,包括他们最近一次购买的时间、购买频率和每次购买的金额。你想要了解哪些客户对你的公司最有价值,以便你能更好地为他们服务。

这时,你可以使用RFM模型来描述每个客户的价值。然后,你可以使用KMeans聚类算法来将这些客户分成几类,比如“高价值客户”(经常购买且每次购买金额都很大)、“中价值客户”(购买频率中等,金额也中等)和“低价值客户”(很少购买或每次购买金额都很小)。

通过这种方式,你就可以根据客户的价值类别来为他们提供个性化的服务或优惠,从而提高客户满意度和忠诚度。

RFM模型

R、F、M

①衡量客户价值的,以便于对客户划分群体

②依据用户近期订单数据(近一个月订单数据、近三个月订单数据)计算得到:

        R:消费周期标签值,最后一次订单距离今天

        F:最近交易次数

        M:最近交易金额

RFM作用直观图

RFM模型小结

一般情况下RFM模型可以说明以下几个事实:

1.最近购买的时间越近,用户对产品促销互动越大 ->  R越小越好

2.客户购买的频率越高,客户就品牌的满意度就越大 ->  F越大越好

3.购买金额(货币价值)将高消费客户和低消费客户区分开来 ->   M 越大越好,以区分高低消费客户

用户划分

到目前为止,我们可以清楚的知道,RFM模型的根本作用就一句话:根据RFM的值,将用户进行权重划分。具体有哪些划分方法?

划分方法:

根据RFM模型(业务数据:订单数据,时间范围内订单数据),就可以统计在某一段时间内,用户最近的消费间隔,消费次数和消费金额,再根据使用 K-Means算法对用户进行聚类分群(不仅仅可以局限于这三个数据字段,还可以根据业务需求,加入其他字段,进行调整模型):

1、划分标准(手动划分)

选择RFM模型中的1-3个指标对客户进行细分,如下表所示。切记细分指标需要在自己可操控的合理范围内,并非越多越好,一旦用户细分群组过多,一来会给自己的营销方案执行带来较大的难度,而来可能会遗漏用户群或者对同个用户造成多次打扰

最终选择多少个指标有两个参考标准:店铺的客户基数,店铺的商品和客户的结构。

2、客户评分(聚类算法划分)

除了直接用RFM模型对用户进行分组以外,还有一种常见的方法时利用RFM模型的三个属性对客户进行打分,通过打分确定每个用户的质量,最终筛选出自己的目标用户。

RFM模型评分主要有三个部分:

  1. 确定RFM三个指标的分段和每个分段的分值;
  2. 计算每个客户RFM三个指标的得分;
  3. 计算每个客户的总得分,并且根据总得分筛选出优质的客户

这里我们采用的是通过聚类算法划分用户,KMeans具体怎么实现下一章会讲,这里主要讲RFM的实现,想了解KMeans算法的请移步KMeans篇

代码实现:

步骤分析

实施步骤

        1.依据用户订单数据计算R、F、M值

                按照用户memberId分组,统计R/F/M的值

        2.按照规则给R、F、M打分

                r_score,f_score,m_score

        3.使用KMeans算法训练模型,K = 5

        4.使用KMeansMode预测用户所属类簇

                Prediction:标识KMeans模型中各类簇中心点下标

        5.结合属性标签规则rule,给用户打标签值(难点)

具体代码

  1. import cn.itcast.tags.models.{AbstractModel, ModelType}
  2. import cn.itcast.tags.tools.TagTools
  3. import org.apache.spark.ml.clustering.{KMeans, KMeansModel}
  4. import org.apache.spark.ml.feature.VectorAssembler
  5. import org.apache.spark.ml.linalg
  6. import org.apache.spark.sql.expressions.UserDefinedFunction
  7. import org.apache.spark.sql.{Column, DataFrame, SparkSession}
  8. import org.apache.spark.sql.functions._
  9. import org.apache.spark.sql.types.{DataTypes, DecimalType}
  10. import org.apache.spark.storage.StorageLevel
  11. /**
  12. * 挖掘类型标签模型开发:客户价值模型RFM
  13. */
  14. class RfmModel extends AbstractModel("客户价值RFM", ModelType.ML){
  15. /*
  16. 361 客户价值
  17. 362 高价值 0
  18. 363 中上价值 1
  19. 364 中价值 2
  20. 365 中下价值 3
  21. 366 超低价值 4
  22. */
  23. override def doTag(businessDF: DataFrame, tagDF: DataFrame): DataFrame = {
  24. val session: SparkSession = businessDF.sparkSession
  25. import session.implicits._
  26. /*
  27. root
  28. |-- memberid: string (nullable = true)
  29. |-- ordersn: string (nullable = true)
  30. |-- orderamount: string (nullable = true)
  31. |-- finishtime: string (nullable = true)
  32. */
  33. //businessDF.printSchema()
  34. //businessDF.show(10, truncate = false)
  35. /*
  36. root
  37. |-- id: long (nullable = false)
  38. |-- name: string (nullable = true)
  39. |-- rule: string (nullable = true)
  40. |-- level: integer (nullable = true)
  41. */
  42. //tagDF.printSchema()
  43. /*
  44. |id |name|rule|level|
  45. +---+----+----+-----+
  46. |362|高价值 |0 |5 |
  47. |363|中上价值|1 |5 |
  48. |364|中价值 |2 |5 |
  49. |365|中下价值|3 |5 |
  50. |366|超低价值|4 |5 |
  51. +---+----+----+-----+
  52. */
  53. //tagDF.filter($"level" === 5).show(10, truncate = false)
  54. /*
  55. TODO: 1、计算每个用户RFM值
  56. 按照用户memberid分组,然后进行聚合函数聚合统计
  57. R:消费周期,finishtime
  58. 日期时间函数:current_timestamp、from_unixtimestamp、datediff
  59. F: 消费次数 ordersn
  60. count
  61. M:消费金额 orderamount
  62. sum
  63. */
  64. val rfmDF: DataFrame = businessDF
  65. // a. 按照memberid分组,对每个用户的订单数据句话操作
  66. .groupBy($"memberid")
  67. .agg(
  68. max($"finishtime").as("max_finishtime"), //
  69. count($"ordersn").as("frequency"), //
  70. sum(
  71. $"orderamount".cast(DataTypes.createDecimalType(10, 2))
  72. ).as("monetary") //
  73. )
  74. // 计算R值
  75. .select(
  76. $"memberid".as("userId"), //
  77. // 计算R值:消费周期
  78. datediff(
  79. current_timestamp(), from_unixtime($"max_finishtime")
  80. ).as("recency"), //
  81. $"frequency", //
  82. $"monetary"
  83. )
  84. //rfmDF.printSchema()
  85. //rfmDF.show(10, truncate = false)
  86. /*
  87. TODO: 2、按照规则给RFM进行打分(RFM_SCORE)
  88. R: 1-3天=5分,4-6天=4分,7-9天=3分,10-15天=2分,大于16天=1分
  89. F: ≥200=5分,150-199=4分,100-149=3分,50-99=2分,1-49=1分
  90. M: ≥20w=5分,10-19w=4分,5-9w=3分,1-4w=2分,<1w=1分
  91. 使用CASE WHEN .. WHEN... ELSE .... END
  92. */
  93. // R 打分条件表达式
  94. val rWhen = when(col("recency").between(1, 3), 5.0) //
  95. .when(col("recency").between(4, 6), 4.0) //
  96. .when(col("recency").between(7, 9), 3.0) //
  97. .when(col("recency").between(10, 15), 2.0) //
  98. .when(col("recency").geq(16), 1.0) //
  99. // F 打分条件表达式
  100. val fWhen = when(col("frequency").between(1, 49), 1.0) //
  101. .when(col("frequency").between(50, 99), 2.0) //
  102. .when(col("frequency").between(100, 149), 3.0) //
  103. .when(col("frequency").between(150, 199), 4.0) //
  104. .when(col("frequency").geq(200), 5.0) //
  105. // M 打分条件表达式
  106. val mWhen = when(col("monetary").lt(10000), 1.0) //
  107. .when(col("monetary").between(10000, 49999), 2.0) //
  108. .when(col("monetary").between(50000, 99999), 3.0) //
  109. .when(col("monetary").between(100000, 199999), 4.0) //
  110. .when(col("monetary").geq(200000), 5.0) //
  111. val rfmScoreDF: DataFrame = rfmDF.select(
  112. $"userId", //
  113. rWhen.as("r_score"), //
  114. fWhen.as("f_score"), //
  115. mWhen.as("m_score") //
  116. )
  117. //rfmScoreDF.printSchema()
  118. //rfmScoreDF.show(50, truncate = false)
  119. /*
  120. TODO: 3、使用RFM_SCORE进行聚类,对用户进行分组
  121. KMeans算法,其中K=5
  122. */
  123. // 3.1 组合R\F\M列为特征值features
  124. val assembler: VectorAssembler = new VectorAssembler()
  125. .setInputCols(Array("r_score", "f_score", "m_score"))
  126. .setOutputCol("features")
  127. val featuresDF: DataFrame = assembler.transform(rfmScoreDF)
  128. // 将训练数据缓存
  129. featuresDF.persist(StorageLevel.MEMORY_AND_DISK)
  130. // 3.2 使用KMeans算法聚类,训练模型
  131. /*
  132. val kMeansModel: KMeansModel = new KMeans()
  133. .setFeaturesCol("features")
  134. .setPredictionCol("prediction") // 由于K=5,所以预测值prediction范围:0,1,2,3,4
  135. // K值设置,类簇个数
  136. .setK(5)
  137. .setMaxIter(20)
  138. .setInitMode("k-means||")
  139. // 训练模型
  140. .fit(featuresDF)
  141. // WSSSE = 0.9977375565642177
  142. println(s"WSSSE = ${kMeansModel.computeCost(featuresDF)}")
  143. */
  144. val kMeansModel: KMeansModel = trainModel(featuresDF)
  145. // 3.3. 使用模型预测
  146. val predictionDF: DataFrame = kMeansModel.transform(featuresDF)
  147. /*
  148. root
  149. |-- userId: string (nullable = true)
  150. |-- r_score: double (nullable = true)
  151. |-- f_score: double (nullable = true)
  152. |-- m_score: double (nullable = true)
  153. |-- features: vector (nullable = true)
  154. |-- prediction: integer (nullable = true)
  155. */
  156. //predictionDF.printSchema()
  157. //predictionDF.show(50, truncate = false)
  158. // 3.4 获取类簇中心点
  159. val centerIndexArray: Array[((Int, Double), Int)] = kMeansModel
  160. .clusterCenters
  161. // 返回值类型:: Array[(linalg.Vector, Int)]
  162. .zipWithIndex // (vector1, 0), (vector2, 1), ....
  163. // TODO: 对每个类簇向量进行累加和:R + F + M
  164. .map{case(clusterVector, clusterIndex) =>
  165. // rfm表示将R + F + M之和,越大表示客户价值越高
  166. val rfm: Double = clusterVector.toArray.sum
  167. clusterIndex -> rfm
  168. }
  169. // 按照rfm值进行降序排序
  170. .sortBy(tuple => - tuple._2)
  171. // 再次进行拉链操作
  172. .zipWithIndex
  173. //centerIndexArray.foreach(println)
  174. // TODO: 4. 打标签
  175. // 4.1 获取属性标签规则rule和名称tagName,放在Map集合中
  176. val rulesMap: Map[String, String] = TagTools.convertMap(tagDF)
  177. //rulesMap.foreach(println)
  178. // 4.2 聚类类簇关联属性标签数据rule,对应聚类类簇与标签tagName
  179. val indexTagMap: Map[Int, String] = centerIndexArray
  180. .map{case((centerIndex, _), index) =>
  181. val tagName = rulesMap(index.toString)
  182. (centerIndex, tagName)
  183. }
  184. .toMap
  185. //indexTagMap.foreach(println)
  186. // 4.3 使用KMeansModel预测值prediction打标签
  187. // a. 将索引标签Map集合 广播变量广播出去
  188. val indexTagMapBroadcast = session.sparkContext.broadcast(indexTagMap)
  189. // b. 自定义UDF函数,传递预测值prediction,返回标签名称tagName
  190. val index_to_tag: UserDefinedFunction = udf(
  191. (clusterIndex: Int) => indexTagMapBroadcast.value(clusterIndex)
  192. )
  193. // c. 打标签
  194. val modelDF: DataFrame = predictionDF.select(
  195. $"userId", // 用户ID
  196. index_to_tag($"prediction").as("rfm")
  197. )
  198. //modelDF.printSchema()
  199. //modelDF.show(100, truncate = false)
  200. // 返回画像标签数据
  201. modelDF
  202. }
  203. /**
  204. * 使用KMeans算法训练模型
  205. * @param dataframe 数据集
  206. * @return KMeansModel模型
  207. */
  208. def trainModel(dataframe: DataFrame): KMeansModel = {
  209. // 使用KMeans聚类算法模型训练
  210. val kMeansModel: KMeansModel = new KMeans()
  211. .setFeaturesCol("features")
  212. .setPredictionCol("prediction")
  213. .setK(5) // 设置列簇个数:5
  214. .setMaxIter(20) // 设置最大迭代次数
  215. .fit(dataframe)
  216. println(s"WSSSE = ${kMeansModel.computeCost(dataframe)}")
  217. // 返回
  218. kMeansModel
  219. }
  220. }
  221. object RfmModel{
  222. def main(args: Array[String]): Unit = {
  223. val tagModel = new RfmModel()
  224. tagModel.executeModel(361L)
  225. }
  226. }

(叠甲:大部分资料来源于黑马程序员,这里只是做一些自己的认识,分享经验,如果大家又不理解的部分请移步【黑马程序员_大数据实战之用户画像企业级项目】https://www.bilibili.com/video/BV1Mp4y1x7y7?p=201&vd_source=07930632bf702f026b5f12259522cb42,以上,大佬勿喷)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/780014
推荐阅读
相关标签
  

闽ICP备14008679号