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

客户价值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,给用户打标签值(难点)

具体代码

import cn.itcast.tags.models.{AbstractModel, ModelType}
import cn.itcast.tags.tools.TagTools
import org.apache.spark.ml.clustering.{KMeans, KMeansModel}
import org.apache.spark.ml.feature.VectorAssembler
import org.apache.spark.ml.linalg
import org.apache.spark.sql.expressions.UserDefinedFunction
import org.apache.spark.sql.{Column, DataFrame, SparkSession}
import org.apache.spark.sql.functions._
import org.apache.spark.sql.types.{DataTypes, DecimalType}
import org.apache.spark.storage.StorageLevel

/**
 * 挖掘类型标签模型开发:客户价值模型RFM
 */
class RfmModel extends AbstractModel("客户价值RFM", ModelType.ML){
	/*
	361	客户价值
		362	高价值		0
		363	中上价值		1
		364	中价值		2
		365	中下价值		3
		366	超低价值		4
	 */
	override def doTag(businessDF: DataFrame, tagDF: DataFrame): DataFrame = {
		val session: SparkSession = businessDF.sparkSession
		import session.implicits._
		
		/*
		root
		 |-- memberid: string (nullable = true)
		 |-- ordersn: string (nullable = true)
		 |-- orderamount: string (nullable = true)
		 |-- finishtime: string (nullable = true)
		 */
		//businessDF.printSchema()
		//businessDF.show(10, truncate = false)
		
		/*
		root
		 |-- id: long (nullable = false)
		 |-- name: string (nullable = true)
		 |-- rule: string (nullable = true)
		 |-- level: integer (nullable = true)
		 */
		//tagDF.printSchema()
		/*
		|id |name|rule|level|
		+---+----+----+-----+
		|362|高价值 |0   |5    |
		|363|中上价值|1   |5    |
		|364|中价值 |2   |5    |
		|365|中下价值|3   |5    |
		|366|超低价值|4   |5    |
		+---+----+----+-----+
		 */
		//tagDF.filter($"level" === 5).show(10, truncate = false)
		
		
		/*
		TODO: 1、计算每个用户RFM值
			按照用户memberid分组,然后进行聚合函数聚合统计
			R:消费周期,finishtime
				日期时间函数:current_timestamp、from_unixtimestamp、datediff
			F: 消费次数 ordersn
				count
			M:消费金额 orderamount
				sum
		 */
		val rfmDF: DataFrame = businessDF
			// a. 按照memberid分组,对每个用户的订单数据句话操作
    		.groupBy($"memberid")
    		.agg(
			    max($"finishtime").as("max_finishtime"), //
			    count($"ordersn").as("frequency"), //
			    sum(
				    $"orderamount".cast(DataTypes.createDecimalType(10, 2))
			    ).as("monetary") //
		    )
			// 计算R值
    		.select(
			    $"memberid".as("userId"), //
			    // 计算R值:消费周期
			    datediff(
				    current_timestamp(), from_unixtime($"max_finishtime")
			    ).as("recency"), //
			    $"frequency", //
			    $"monetary"
		    )
		//rfmDF.printSchema()
		//rfmDF.show(10, truncate = false)
		
		/*
		TODO: 2、按照规则给RFM进行打分(RFM_SCORE)
			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分
			
			使用CASE WHEN ..  WHEN... ELSE .... END
		 */
		// R 打分条件表达式
		val rWhen = when(col("recency").between(1, 3), 5.0) //
			.when(col("recency").between(4, 6), 4.0) //
			.when(col("recency").between(7, 9), 3.0) //
			.when(col("recency").between(10, 15), 2.0) //
			.when(col("recency").geq(16), 1.0) //
		// F 打分条件表达式
		val fWhen = when(col("frequency").between(1, 49), 1.0) //
			.when(col("frequency").between(50, 99), 2.0) //
			.when(col("frequency").between(100, 149), 3.0) //
			.when(col("frequency").between(150, 199), 4.0) //
			.when(col("frequency").geq(200), 5.0) //
		// M 打分条件表达式
		val mWhen = when(col("monetary").lt(10000), 1.0) //
			.when(col("monetary").between(10000, 49999), 2.0) //
			.when(col("monetary").between(50000, 99999), 3.0) //
			.when(col("monetary").between(100000, 199999), 4.0) //
			.when(col("monetary").geq(200000), 5.0) //
		val rfmScoreDF: DataFrame = rfmDF.select(
			$"userId", //
			rWhen.as("r_score"), //
			fWhen.as("f_score"), //
			mWhen.as("m_score") //
		)
		//rfmScoreDF.printSchema()
		//rfmScoreDF.show(50, truncate = false)
		
		/*
		TODO: 3、使用RFM_SCORE进行聚类,对用户进行分组
			KMeans算法,其中K=5
		 */
		// 3.1 组合R\F\M列为特征值features
		val assembler: VectorAssembler = new VectorAssembler()
			.setInputCols(Array("r_score", "f_score", "m_score"))
			.setOutputCol("features")
		val featuresDF: DataFrame = assembler.transform(rfmScoreDF)
		// 将训练数据缓存
		featuresDF.persist(StorageLevel.MEMORY_AND_DISK)
		
		// 3.2 使用KMeans算法聚类,训练模型
		/*
			val kMeansModel: KMeansModel = new KMeans()
				.setFeaturesCol("features")
				.setPredictionCol("prediction") // 由于K=5,所以预测值prediction范围:0,1,2,3,4
				// K值设置,类簇个数
				.setK(5)
				.setMaxIter(20)
				.setInitMode("k-means||")
				// 训练模型
				.fit(featuresDF)
			// WSSSE = 0.9977375565642177
			println(s"WSSSE = ${kMeansModel.computeCost(featuresDF)}")
		*/
		val kMeansModel: KMeansModel = trainModel(featuresDF)
		
		// 3.3. 使用模型预测
		val predictionDF: DataFrame = kMeansModel.transform(featuresDF)
		/*
		root
		 |-- userId: string (nullable = true)
		 |-- r_score: double (nullable = true)
		 |-- f_score: double (nullable = true)
		 |-- m_score: double (nullable = true)
		 |-- features: vector (nullable = true)
		 |-- prediction: integer (nullable = true)
		 */
		//predictionDF.printSchema()
		//predictionDF.show(50, truncate = false)
		
		// 3.4 获取类簇中心点
		val centerIndexArray: Array[((Int, Double), Int)] = kMeansModel
			.clusterCenters
			// 返回值类型:: Array[(linalg.Vector, Int)]
    		.zipWithIndex // (vector1, 0), (vector2, 1), ....
			// TODO: 对每个类簇向量进行累加和:R + F + M
			.map{case(clusterVector, clusterIndex) =>
				// rfm表示将R + F + M之和,越大表示客户价值越高
				val rfm: Double = clusterVector.toArray.sum
				clusterIndex -> rfm
			}
			// 按照rfm值进行降序排序
			.sortBy(tuple => - tuple._2)
			// 再次进行拉链操作
			.zipWithIndex
		//centerIndexArray.foreach(println)
		
		// TODO: 4. 打标签
		// 4.1 获取属性标签规则rule和名称tagName,放在Map集合中
		val rulesMap: Map[String, String] = TagTools.convertMap(tagDF)
		//rulesMap.foreach(println)
		
		// 4.2 聚类类簇关联属性标签数据rule,对应聚类类簇与标签tagName
		val indexTagMap: Map[Int, String] = centerIndexArray
			.map{case((centerIndex, _), index) =>
				val tagName = rulesMap(index.toString)
				(centerIndex, tagName)
			}
			.toMap
		//indexTagMap.foreach(println)
		
		// 4.3 使用KMeansModel预测值prediction打标签
		// a. 将索引标签Map集合 广播变量广播出去
		val indexTagMapBroadcast = session.sparkContext.broadcast(indexTagMap)
		// b. 自定义UDF函数,传递预测值prediction,返回标签名称tagName
		val index_to_tag: UserDefinedFunction = udf(
			(clusterIndex: Int) => indexTagMapBroadcast.value(clusterIndex)
		)
		// c. 打标签
		val modelDF: DataFrame = predictionDF.select(
			$"userId", // 用户ID
			index_to_tag($"prediction").as("rfm")
		)
		//modelDF.printSchema()
		//modelDF.show(100, truncate = false)
		
		// 返回画像标签数据
		modelDF
	}
	
	/**
	 * 使用KMeans算法训练模型
	 * @param dataframe 数据集
	 * @return KMeansModel模型
	 */
	def trainModel(dataframe: DataFrame): KMeansModel = {
		// 使用KMeans聚类算法模型训练
		val kMeansModel: KMeansModel = new KMeans()
			.setFeaturesCol("features")
			.setPredictionCol("prediction")
			.setK(5) // 设置列簇个数:5
			.setMaxIter(20) // 设置最大迭代次数
			.fit(dataframe)
		println(s"WSSSE = ${kMeansModel.computeCost(dataframe)}")
		
		// 返回
		kMeansModel
	}
}

object RfmModel{
	def main(args: Array[String]): Unit = {
		val tagModel = new RfmModel()
		tagModel.executeModel(361L)
	}
}

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

  • 26
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
根据引用\[1\]和\[2\]的内容,RFM模型是一种用于分析客户价值的模型,它使用了一些直接相关的变量来描述用户特征。然而,这些变量并不能完全涵盖用户特征,因此可以使用K-Means聚类算法引入其他变量来进一步分析不同类别客户的特征。在K-Means聚类分析中,首先选取了一些重要的指标来刻画用户,然后对这些指标进行了数据标准化,接着使用K-Means算法进行聚类,得到了每个分类的质心。最后,根据质心和用户特征,可以得到用户画像表,用于描述不同类别客户的特征。\[2\] 根据引用\[3\]的内容,为了确定K-Means聚类的簇数,可以使用肘方法。在肘方法中,选择斜率开始缓慢下降的点作为簇数。在这个例子中,选择了3作为K-Means的簇数。然后,使用K-Means算法进行聚类,并计算每个簇下的R、F、M值的平均值。\[3\] 综上所述,通过RFM模型和K-Means聚类分析,可以对客户进行细分,并了解不同类别客户的特征。 #### 引用[.reference_title] - *1* *2* [K-Means聚类分析--RFM模型](https://blog.csdn.net/lau143/article/details/112604862)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [基于产品的RFM模型的k-means聚类分析](https://blog.csdn.net/foxirensheng/article/details/122704512)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值