用戶畫像 - 挖掘標簽

RFM 用戶價值模型

1 需求

用戶畫像

  • 假設(shè)我是一個市場營銷者, 在做一次活動之前, 我可能會思考如下問題
  • 誰是我比較有價值的客戶?
  • 誰是比較有潛力成為有價值的客戶?
  • 誰快要流失了?
  • 誰能夠留下來?
  • 誰會關(guān)心這次活動?
  • 其實上面這些思考, 都圍繞一個主題 價值
  • RFM 是一個最常見的用來評估價值的和潛在價值的工具

2 RFM 是什么RFM

  • 通過最后一次消費距今時間, 單位時間內(nèi)的消費頻率, 平均消費金額來評估一個人對公司的價值, 可以理解為 RFM 是一個集成的值, 如下RFM = Rencency(最后一次消費時間), Frequency(消費頻率), Monetary(消費金額)
  • RFM 模型可以說明如下事實:
  • 最近一次購買時間越近, 用戶對促銷越有感
  • 購買頻率越高, 對我們滿意度就越高
  • 消費金額越大, 越有錢, 越是高消費人群
    RFM模型

    3 RFM的實際應(yīng)用
    RFM實際應(yīng)用

4 高維空間模型

高維空間模型

5 通過打分統(tǒng)一量綱

  • 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 模型訓(xùn)練與預(yù)測

  • RFMTrainModel 訓(xùn)練模型, 保存模型到 HDFS 中, 調(diào)度周期, 一個月執(zhí)行一次
  • RFMPredictModel 預(yù)測模型, 從 HDFS 中讀取聚類模型, 對整個數(shù)據(jù)集進行預(yù)測, 每天一次
 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 之間的關(guān)系
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 (特定時間內(nèi)訪問頻率) + E (活動數(shù)量)
  • 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 用于統(tǒng)計用戶的價格敏感度
  • 對于不同級別價格敏感的用戶可以實行不同程度的營銷

1 PSM計算公式

  • PSM Score = 優(yōu)惠訂單占比 + (平均優(yōu)惠金額 / 平均每單應(yīng)收) + 優(yōu)惠金額占比
  • 優(yōu)惠訂單占比
  • 優(yōu)惠訂單 / 總單數(shù)
  • 優(yōu)惠訂單 = 優(yōu)惠的訂單數(shù)量 / 總單數(shù)
  • 未優(yōu)惠訂單 = 未優(yōu)惠的訂單數(shù)量 / 總單數(shù)
  • 平均優(yōu)惠金額
  • 總優(yōu)惠金額 / 優(yōu)惠單數(shù)
  • 平均每單應(yīng)收
  • 總應(yīng)收 / 總單數(shù)
  • 優(yōu)惠金額占比
  • 總優(yōu)惠金額 / 總應(yīng)收金額
// 應(yīng)收金額
val receivableAmount = ('couponCodeValue + 'orderAmount).cast(DoubleType) as "receivableAmount"
// 優(yōu)惠金額
val discountAmount = 'couponCodeValue.cast(DoubleType) as "discountAmount"
// 實收金額
val practicalAmount = 'orderAmount.cast(DoubleType) as "practicalAmount"
// 是否優(yōu)惠
val state = when(discountAmount =!= 0.0d, 1) // =!=是column的方法
  .when(discountAmount === 0.0d, 0)
  .as("state")

// 優(yōu)惠訂單數(shù)
val discountCount = sum('state) as "discountCount"
// 訂單總數(shù)
val totalCount = count('state) as "totalCount"
// 優(yōu)惠總額
val totalDiscountAmount = sum('discountAmount) as "totalDiscountAmount"
// 應(yīng)收總額
val totalReceivableAmount = sum('receivableAmount) as "totalReceivableAmount"

// 平均優(yōu)惠金額
val avgDiscountAmount = ('totalDiscountAmount / 'discountCount) as "avgDiscountAmount"
// 平均每單應(yīng)收
val avgReceivableAmount = ('totalReceivableAmount / 'totalCount) as "avgReceivableAmount"
// 優(yōu)惠訂單占比
val discountPercent = ('discountCount / 'totalCount) as "discountPercent"
// 平均優(yōu)惠金額占比
val avgDiscountPercent = (avgDiscountAmount / avgReceivableAmount) as "avgDiscountPercent"
// 優(yōu)惠金額占比
val discountAmountPercent = ('totalDiscountAmount / 'totalReceivableAmount) as "discountAmountPercent"

// 優(yōu)惠訂單占比 + (平均優(yōu)惠金額 / 平均每單應(yīng)收) + 優(yōu)惠金額占比
val psmScore = (discountPercent + (avgDiscountPercent / avgReceivableAmount) + discountAmountPercent) as "psm"

2 聚類算法原理

  • 選擇 K 個點作為初始中點
  • 計算每個中點到相近點的距離, 將相近的點聚在一類(簇)
  • 歐式距離
  • 重新計算每個簇的中點
  • 重復(fù)迭代上面步驟, 直至不再發(fā)生變化


    聚類算法原理

3 確定K - 肘部法則

  • 根據(jù)損失函數(shù), 計算每一個 K 的情況下, 總體上的損失
  • 繪制圖形, 找到拐點, 就是合適的 K


    肘部法則

4 模型訓(xùn)練與迭代計算

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計算損失函數(shù)
  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

分類模型-預(yù)測性別

  • 購物性別模型的意義有兩種:
  • 通過用戶購物的行為, 預(yù)測用戶性別
  • 通過用戶購物的行為, 判定用戶的購物性別偏好

1 預(yù)置標簽,量化屬性

|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 決策樹算法

  • 決策樹是一個監(jiān)督學(xué)習(xí)算法, 需要先對數(shù)據(jù)集人工打上標簽, 此處簡化整體流程, 通過簡單的匹配, 先預(yù)置所需要的標簽


    決策樹算法模型

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")//精準度
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容