用户画像 - 挖掘标签
  xP7vvuQeeYuv 2023年11月02日 36 0


RFM 用户价值模型

1 需求

用户画像 - 挖掘标签_智能电视

  • 假设我是一个市场营销者, 在做一次活动之前, 我可能会思考如下问题
  • 谁是我比较有价值的客户?
  • 谁是比较有潜力成为有价值的客户?
  • 谁快要流失了?
  • 谁能够留下来?
  • 谁会关心这次活动?
  • 其实上面这些思考, 都围绕一个主题 价值
  • RFM 是一个最常见的用来评估价值的和潜在价值的工具

2 RFM 是什么RFM

  • 通过最后一次消费距今时间, 单位时间内的消费频率, 平均消费金额来评估一个人对公司的价值, 可以理解为 RFM 是一个集成的值, 如下RFM = Rencency(最后一次消费时间), Frequency(消费频率), Monetary(消费金额)
  • RFM 模型可以说明如下事实:
  • 最近一次购买时间越近, 用户对促销越有感
  • 购买频率越高, 对我们满意度就越高
  • 消费金额越大, 越有钱, 越是高消费人群

    3 RFM的实际应用

    4 高维空间模型

    5 通过打分统一量纲
  • 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分
val rScore: Column = when('r.>=(1).and('r.<=(3)), 5)
  .when('r >= 4 and 'r <= 6, 4)
  .when('r >= 7 and 'r <= 9, 3)
  .when('r >= 10 and 'r <= 15, 2)
  .when('r >= 16, 1)
  .as("r_score")

val fScore: Column = when('f >= 200, 5)
  .when(('f >= 150) && ('f <= 199), 4)
  .when((col("f") >= 100) && (col("f") <= 149), 3)
  .when((col("f") >= 50) && (col("f") <= 99), 2)
  .when((col("f") >= 1) && (col("f") <= 49), 1)
  .as("f_score")

val mScore: Column = when(col("m") >= 200000, 5)
  .when(col("m").between(100000, 199999), 4)
  .when(col("m").between(50000, 99999), 3)
  .when(col("m").between(10000, 49999), 2)
  .when(col("m") <= 9999, 1)
  .as("m_score")

6 模型训练与预测

  • RFMTrainModel 训练模型, 保存模型到 HDFS 中, 调度周期, 一个月执行一次
  • RFMPredictModel 预测模型, 从 HDFS 中读取聚类模型, 对整个数据集进行预测, 每天一次
def process(source: DataFrame): DataFrame = {
  val assembled = assembleDataFrame(source)
     val regressor = new KMeans()
     .setK(7)
     .setSeed(10)
     .setMaxIter(10)
     .setFeaturesCol("features")
     .setPredictionCol("predict")

   regressor.fit(assembled).save(MODEL_PATH)

  null
}
val assembled = RFMModel.assembleDataFrame(source)

val kmeans = KMeansModel.load(RFMModel.MODEL_PATH)
val predicted = kmeans.transform(assembled)

// 找到 kmeans 生成的组号和 rule 之间的关系
val sortedCenters: IndexedSeq[(Int, Double)] = kmeans.clusterCenters.indices // IndexedSeq
  .map(i => (i, kmeans.clusterCenters(i).toArray.sum))
  .sortBy(c => c._2).reverse

val sortedDF = sortedCenters.toDF("index", "totalScore")

RFE 活跃度

  • 类似 RFM, 我们使用 RFE 计算用户的活跃度
  • RFE = R (最近一次访问时间) + F (特定时间内访问频率) + E (活动数量)
  • R = datediff(date_sub(current_timestamp(),60), max('log_time))
  • F = count('loc_url)
  • E = countDistinct('loc_url)
  • R:0-15天=5分,16-30天=4分,31-45天=3分,46-60天=2分,大于61天=1分
  • F:≥400=5分,300-399=4分,200-299=3分,100-199=2分,≤99=1分
  • E:≥250=5分,230-249=4分,210-229=3分,200-209=2分,1=1分

PSM 价格敏感度模型

  • PSM 用于统计用户的价格敏感度
  • 对于不同级别价格敏感的用户可以实行不同程度的营销

1 PSM计算公式

  • PSM Score = 优惠订单占比 + (平均优惠金额 / 平均每单应收) + 优惠金额占比
  • 优惠订单占比
  • 优惠订单 / 总单数
  • 优惠订单 = 优惠的订单数量 / 总单数
  • 未优惠订单 = 未优惠的订单数量 / 总单数
  • 平均优惠金额
  • 总优惠金额 / 优惠单数
  • 平均每单应收
  • 总应收 / 总单数
  • 优惠金额占比
  • 总优惠金额 / 总应收金额
// 应收金额
val receivableAmount = ('couponCodeValue + 'orderAmount).cast(DoubleType) as "receivableAmount"
// 优惠金额
val discountAmount = 'couponCodeValue.cast(DoubleType) as "discountAmount"
// 实收金额
val practicalAmount = 'orderAmount.cast(DoubleType) as "practicalAmount"
// 是否优惠
val state = when(discountAmount =!= 0.0d, 1) // =!=是column的方法
  .when(discountAmount === 0.0d, 0)
  .as("state")

// 优惠订单数
val discountCount = sum('state) as "discountCount"
// 订单总数
val totalCount = count('state) as "totalCount"
// 优惠总额
val totalDiscountAmount = sum('discountAmount) as "totalDiscountAmount"
// 应收总额
val totalReceivableAmount = sum('receivableAmount) as "totalReceivableAmount"

// 平均优惠金额
val avgDiscountAmount = ('totalDiscountAmount / 'discountCount) as "avgDiscountAmount"
// 平均每单应收
val avgReceivableAmount = ('totalReceivableAmount / 'totalCount) as "avgReceivableAmount"
// 优惠订单占比
val discountPercent = ('discountCount / 'totalCount) as "discountPercent"
// 平均优惠金额占比
val avgDiscountPercent = (avgDiscountAmount / avgReceivableAmount) as "avgDiscountPercent"
// 优惠金额占比
val discountAmountPercent = ('totalDiscountAmount / 'totalReceivableAmount) as "discountAmountPercent"

// 优惠订单占比 + (平均优惠金额 / 平均每单应收) + 优惠金额占比
val psmScore = (discountPercent + (avgDiscountPercent / avgReceivableAmount) + discountAmountPercent) as "psm"

2 聚类算法原理

  • 选择 K 个点作为初始中点
  • 计算每个中点到相近点的距离, 将相近的点聚在一类(簇)
  • 欧式距离
  • 重新计算每个簇的中点
  • 重复迭代上面步骤, 直至不再发生变化

3 确定K - 肘部法则

  • 根据损失函数, 计算每一个 K 的情况下, 总体上的损失
  • 绘制图形, 找到拐点, 就是合适的 K

4 模型训练与迭代计算

val kArray = Array(2, 3, 4, 5, 6, 7, 8)
val wssseMap = kArray.map(f = k => {
  val kmeans = new KMeans()
    .setK(k)
    .setMaxIter(10)
    .setPredictionCol("prediction")
    .setFeaturesCol("features")
  val model: KMeansModel = kmeans.fit(vectored)

  import spark.implicits._
  // mlLib计算损失函数
  val vestors: Array[OldVector] = model.clusterCenters.map(v => OldVectors.fromML(v))
  val libModel: LibKMeansModel = new LibKMeansModel(vestors)
  val features = vectored.rdd.map(row => {
    val ve = row.getAs[Vector]("features")
    val oldVe: OldVector = OldVectors.fromML(ve)
    oldVe
  })

  val wssse: Double = libModel.computeCost(features)
  (k, wssse)
}).toMap

分类模型-预测性别

  • 购物性别模型的意义有两种:
  • 通过用户购物的行为, 预测用户性别
  • 通过用户购物的行为, 判定用户的购物性别偏好

1 预置标签,量化属性

|memberId| color|productType|gender|colorIndex|  color|    productType|gender|productTypeIndex|   features|featuresIndex|
+--------+------+-----------+------+----------+------------------+---------------+------+----------------+-----------+-------------+
|       4|樱花粉|   智能电视|     1|      14.0|樱花粉|       智能电视|     1|            13.0|[14.0,13.0]|  [14.0,13.0]|
|       4|樱花粉|   智能电视|     1|      14.0|  蓝色| Haier/海尔冰箱|     0|             1.0| [14.0,1.0]|   [14.0,1.0]|
val label = when('ogColor.equalTo("樱花粉")
  .or('ogColor.equalTo("白色"))
  .or('ogColor.equalTo("香槟色"))
  .or('ogColor.equalTo("香槟金"))
  .or('productType.equalTo("料理机"))
  .or('productType.equalTo("挂烫机"))
  .or('productType.equalTo("吸尘器/除螨仪")), 1)
  .otherwise(0)
  .alias("gender")

2 决策树算法

  • 决策树是一个监督学习算法, 需要先对数据集人工打上标签, 此处简化整体流程, 通过简单的匹配, 先预置所需要的标签

3 算法工程与模型评估

val featureVectorIndexer = new VectorIndexer()
  .setInputCol("features")
  .setOutputCol("featuresIndex")
  .setMaxCategories(3)

val decisionTreeClassifier = new DecisionTreeClassifier()
  .setFeaturesCol("featuresIndex")
  .setLabelCol("gender")
  .setPredictionCol("predict")
  .setMaxDepth(5)
  .setImpurity("gini")

val pipeline = new Pipeline()
  .setStages(Array(colorIndexer, productTypeIndexer, featureAssembler, featureVectorIndexer, decisionTreeClassifier))

val Array(trainData, testData) = source.randomSplit(Array(0.8, 0.2))

val model: PipelineModel = pipeline.fit(trainData)
 val pTrain = model.transform(trainData)
 val tTrain = model.transform(testData)

val accEvaluator = new MulticlassClassificationEvaluator()
  .setPredictionCol("predict")
  .setLabelCol("gender")
  .setMetricName("accuracy")//精准度


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  F36IaJwrKLcw   2023年12月23日   42   0   0 idesparkidesparkDataData
  r3WP0l4Uu2vq   2023年12月23日   36   0   0 sqlsparksparkSQL
xP7vvuQeeYuv
最新推荐 更多

2024-05-31