既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如下图, 对“便宜”和“太便宜”向下累计百分数(因为价格越低消费者越觉得便宜,即认为某价格便宜的消费者也会认为低于此价格的价格便宜),“贵”和“太贵”向上累计百分数(因为价格越高消费者越觉得贵,即认为某价格贵的消费者也会认为高于此价格的价格贵),能够得到四条累计百分比曲线。
“太便宜”和“贵”的交点意味着此价格能够让最多的人觉得“不会便宜到影响购买意愿,即使可能有点贵也是能够接受的”,“便宜”和“太贵”的交点意味着此价格能够让最多的人觉得“不会贵到不能接受,还是挺划算的”,因此这两个交点分别为价格区间的下限和上限。低于前者,消费者会因为担心“过于大众不能体现优越感,或会给游戏带来不好影响(如游戏平衡性)”而不愿购买;高于后者,消费者会认为价钱太高而不能接受。
一般来说,“太便宜”和“太贵”的交点作为最优价格点,因为在此处觉得“不过于便宜也不过于昂贵”的消费者最多。但是也有人认为“便宜”和“贵”的交点是最优价格,因为该交点取得了“划算,肯定会买”及“贵,但能接受”的平衡点,是能让最多消费者满意的价格。
PSM模型的缺陷及解决
- 存在的问题
第一:只考虑到了消费者的接受率,忽视了消费者的购买能力,即只追求最大的目标人群数。但事实上,即使消费者觉得价格合理,受限于购买力等因素,也无法购买。
第二:研究中消费者可能出于各种因素(比如让价格更低能让自己收益,出于面子问题而抬高自己能接受的价格等)有意或无意地抬高或压低其接受的价格。由于消费者知道虚拟世界中的产品(道具或服务)没有成本,其压低价格的可能性较高。
第三:没有考虑价格变化导致的购买意愿(销量)变化。
- 解决方案
第一:为了避免购买力的影响, 问卷或访谈研究中要强调“定这个价格,以自己目前的情况是否会购买”,而非仅仅去客观判断该产品值多少钱。
第二:为了解决玩家抬高或压低价格的问题,可以增大样本量,预期随机误差可以相互抵消。
第三:仅仅从曲线获得最优价格,受到玩家压低或抬高价格的影响较大。由于该误差可能是系统误差,对此,可以用所获得的价格区间设计不同的价格方案,然后设计组间实验设计,每个参与研究的消费者只接触其中一种或几种价格方案,并对该价格方案下是否购买及购买数量做出决策,通过计算那种价格方案下玩家消费金钱量最高来分析出最佳价格方案。如下表。
第四:通过前一条中提到的组间实验设计,可以计算出不同价格下玩家购买意愿的变化,从而得知价格调整会对整体收益带来的影响。此外,价格接受比例还可以作为消费者对某价格满意度的指标,用于计算某价格下企业该产品的良性收益。
注意,我们的上述对策部分基于统计学和实验心理学理论,部分基于我们工作中的实践,欢迎大家讨论和优化。
以上都是基于大量理论后得出的结果,下面我们来结合用户画像的项目,来“模拟”商家给不同价格敏感度的用户打上不同标签的过程。
用户画像
首先我们在web页面,先添加上我们本次需要给用户开发的标签和标签值。
查看数据库
现在有了数据,我们本该就可以直接上手代码了。但为了简便开发,避免重复的步骤,我们先来分析一下业务需求。
业务分析
我们如果要实现根据不同的人给出不同的价格,那么如何才能确定用户的价格敏感度( PSM
)?
这里有一个公式:
psm = 优惠订单占比 + 平均优惠金额占比 + 优惠总金额占比
是不是刚看有点懵,我们再来细化一下。
优惠订单占比 = 优惠次数/总购买次数
平均优惠金额占比 = 平均优惠金额/平均应收金额
平均优惠金额=优惠总金额/优惠总次数
平均应收金额 = 应收总金额 /订单总次数
优惠总金额占比 = 优惠总金额/应收总金额
综上所述,我们可以将计算PSM的目标进一步变成计算以下四个数据,只要将它们计算出来,PSM就迎刃而解。
优惠次数
总购买次数
优惠总金额
应收总金额
前三个数据,我们可以提供统计型函数计算得出, 而 应收总金额= 优惠金额 + 成交金额 这一点我们明确了之后,就可以很好的上手代码了。
业务代码
算上这次,博主已经是第三次开发挖掘型标签了。所以就不单独把每一步具体实现的业务拿出来慢慢叙述了。更多的细节已经每步实现的效果已经用注释的方式贴在代码中了,有兴趣尝试的朋友,或者想要借鉴结果的朋友可以一睹代码究竟。
import com.czxy.base.BaseModel
import org.apache.spark.ml.clustering.{KMeans, KMeansModel}
import org.apache.spark.ml.feature.VectorAssembler
import org.apache.spark.sql._
import org.apache.spark.sql.expressions.UserDefinedFunction
import scala.collection.immutable
/\*
\* @Author: Alice菌
\* @Date: 2020/6/26 11:17
\* @Description:
基于PSM模型,对用户的价格敏感度进行挖掘
\*/
object PSMModel extends BaseModel {
override def setAppName: String = "PSMModel"
override def setFourTagId: String = "181"
override def getNewTag(spark: SparkSession, fiveTagDF: DataFrame, hbaseDF: DataFrame): DataFrame = {
// 五级标签的数据
fiveTagDF.show()
//+---+----+
//| id|rule|
//+---+----+
//|182| 1|
//|183| 2|
//|184| 3|
//|185| 4|
//|186| 5|
//+---+----+
// HBase的数据
hbaseDF.show()
//+---------+--------------------+-----------+---------------+
//| memberId| orderSn|orderAmount|couponCodeValue|
//+---------+--------------------+-----------+---------------+
//| 13823431|gome\_792756751164275| 2479.45| 0.00|
//| 4035167|jd\_14090106121770839| 2449.00| 0.00|
//| 4035291|jd\_14090112394810659| 1099.42| 0.00|
//| 4035041|amazon\_7877495617...| 1999.00| 0.00|
// tdonr 优惠订单占比(优惠订单数 / 订单总数)
// adar 平均优惠金额占比(平均优惠金额 / 平均每单应收金额)
// tdar 优惠金额占比(优惠总金额 / 订单总金额)
//psm = 优惠订单占比 + 平均优惠金额占比 + 优惠总金额占比
//只需要求取下面的字段,即可获取到最终的结果
//优惠次数
//总购买次数
//优惠总金额
//应收总金额 = 优惠金额+成交金额
// 引入隐式转换
import spark.implicits._
//引入java 和scala相互转换
import scala.collection.JavaConverters._
//引入sparkSQL的内置函数
import org.apache.spark.sql.functions._
// 优惠次数
var preferentialCount:String = "preferential"
// 订单总数
var orderCount:String = "orderCount"
// 总优惠金额
var couponCodeValue:String = "couponCodeValue"
// 应收总金额
var totalValue:String = "totalValue"
// 优惠次数
var getPreferentialCount:Column= count(
when(col("couponCodeValue") !== 0.00,1)
) as preferentialCount
// 总购买次数
val getOrderCount: Column = count("orderSn") as orderCount
// 优惠总金额
var getCouponCodeValue:Column= sum("couponCodeValue") as couponCodeValue
// 应收总金额
var getTotalValue: Column = (sum("orderAmount") + sum("couponCodeValue") ) as totalValue
// 特征单词
val featureStr: String = "feature" // 向量
val predictStr: String = "predict" // 分类
// 进行查询
val getPSMDF01: DataFrame = hbaseDF.groupBy("memberId")
.agg(getPreferentialCount, getOrderCount, getCouponCodeValue,getTotalValue)
//展示结果
getPSMDF01.show(5)
//+---------+------------+-----------+---------------+------------------+
//| memberId|preferential|orderAmount|couponCodeValue| totalValue|
//+---------+------------+-----------+---------------+------------------+
//| 4033473| 3| 142| 500.0|252430.91999999998|
//| 13822725| 4| 116| 800.0| 180098.34|
//| 13823681| 1| 108| 200.0|169946.09999999998|
//|138230919| 3| 125| 600.0|240661.56999999998|
//| 13823083| 3| 132| 600.0| 234124.17|
//+---------+------------+-----------+---------------+------------------+
// 先设置上我们常用的单词
// 优惠订单占比
var preferentiaOrderlPro:String = "preferentiaOrderlPro"
// 平均优惠金额占比
var avgPreferentialPro:String = "avgPreferentialPro"
// 优惠金额占比
val preferentialMoneyPro: String = "preferentialMoneyPro"
/\* 获取到想要的字段结果 \*/
// 优惠订单占比(优惠订单数 / 订单总数)
val getPSMDF02: DataFrame = getPSMDF01.select(col("memberId"),col("preferential") / col("orderCount") as preferentiaOrderlPro,
// 平均优惠金额占比(平均优惠金额 / 平均每单应收金额)
(col("couponCodeValue") / col("preferential")) / (col("totalValue") / col("orderCount")) as avgPreferentialPro,
// 优惠金额占比(优惠总金额 / 订单总金额)
col("couponCodeValue") / col("totalValue") as preferentialMoneyPro)
getPSMDF02.show()
//+---------+--------------------+-------------------+--------------------+
//| memberId|preferentiaOrderlPro| avgPreferentialPro|preferentialMoneyPro|
//+---------+--------------------+-------------------+--------------------+
//| 4033473| 0.02112676056338028|0.09375502282631092|0.001980739918865724|
//| 13822725|0.034482758620689655| 0.1288185110423561| 0.00444201762215021|
//| 13823681|0.009259259259259259|0.12709912142732316|0.001176843716919...|
//|138230919| 0.024|0.10388031624658645|0.002493127589918075|
//| 13823083|0.022727272727272728|0.11276067737901643|0.002562742667704919|
//| 13823431| 0.01639344262295082|0.13461458465166434|0.002206796469699...|
//| 4034923|0.009259259259259259|0.12882071966768546|0.001192784441367458|
//| 4033575| 0.032|0.07938713328518321|0.002540388265125...|
//| 13822841| 0.0| null| 0.0|
val getPSMDF03: DataFrame = getPSMDF02.select(col("memberId"),col("preferentiaOrderlPro"),col("avgPreferentialPro"),col("preferentialMoneyPro"),(col("preferentiaOrderlPro")+col("avgPreferentialPro")+col("preferentialMoneyPro")) as "PSM" ).filter('PSM isNotNull)
getPSMDF03.show()
//+---------+--------------------+-------------------+--------------------+-------------------+
//| memberId|preferentiaOrderlPro| avgPreferentialPro|preferentialMoneyPro| PSM|
//+---------+--------------------+-------------------+--------------------+-------------------+
//| 4033473| 0.02112676056338028|0.09375502282631092|0.001980739918865724|0.11686252330855693|
//| 13822725|0.034482758620689655| 0.1288185110423561| 0.00444201762215021|0.16774328728519597|
//| 13823681|0.009259259259259259|0.12709912142732316|0.001176843716919...|0.13753522440350205|
//|138230919| 0.024|0.10388031624658645|0.002493127589918075| 0.1303734438365045|
//| 13823083|0.022727272727272728|0.11276067737901643|0.002562742667704919| 0.1380506927739941|
// 为了方便K-Means计算,我们将数据转换成向量
val PSMFeature: DataFrame = new VectorAssembler()
.setInputCols(Array("PSM"))
.setOutputCol(featureStr)
.transform(getPSMDF03)
PSMFeature.show()
//+---------+--------------------+--------------------+--------------------+-------------------+--------------------+
//| memberId|preferentiaOrderlPro| avgPreferentialPro|preferentialMoneyPro| PSM| feature|
//+---------+--------------------+--------------------+--------------------+-------------------+--------------------+
//| 4033473| 0.02112676056338028| 0.09375502282631092|0.001980739918865724|0.11686252330855693|[0.11686252330855...|
//| 13822725|0.034482758620689655| 0.1288185110423561| 0.00444201762215021|0.16774328728519597|[0.16774328728519...|
//| 13823681|0.009259259259259259| 0.12709912142732316|0.001176843716919...|0.13753522440350205|[0.13753522440350...|
//|138230919| 0.024| 0.10388031624658645|0.002493127589918075| 0.1303734438365045|[0.1303734438365045]|
//| 13823083|0.022727272727272728| 0.11276067737901643|0.002562742667704919| 0.1380506927739941|[0.1380506927739941]|
//| 13823431| 0.01639344262295082| 0.13461458465166434|0.002206796469699...|0.15321482374431458|[0.15321482374431...|
//| 4034923|0.009259259259259259| 0.12882071966768546|0.001192784441367458|0.13927276336831218|[0.13927276336831...|
//| 4033575| 0.032| 0.07938713328518321|0.002540388265125...|0.11392752155030907|[0.11392752155030...|
//| 13823153|0.045112781954887216| 0.10559805877421218|0.004763822200340399|0.15547466292943982|[0.15547466292943...|
// 利用KMeans算法,进行数据的分类
val KMeansModel: KMeansModel = new KMeans()
.setK(5) // 设置4类
.setMaxIter(5) // 迭代计算5次
.setFeaturesCol(featureStr) // 设置特征数据
.setPredictionCol(predictStr) // 计算完毕后的标签结果
.fit(PSMFeature)
// 将其转换成DF
val KMeansModelDF: DataFrame = KMeansModel.transform(PSMFeature)
KMeansModelDF.show()
//+---------+--------------------+--------------------+--------------------+-------------------+--------------------+-------+
//| memberId|preferentiaOrderlPro| avgPreferentialPro|preferentialMoneyPro| PSM| feature|predict|
//+---------+--------------------+--------------------+--------------------+-------------------+--------------------+-------+
//| 4033473| 0.02112676056338028| 0.09375502282631092|0.001980739918865724|0.11686252330855693|[0.11686252330855...| 4|
//| 13822725|0.034482758620689655| 0.1288185110423561| 0.00444201762215021|0.16774328728519597|[0.16774328728519...| 4|
//| 13823681|0.009259259259259259| 0.12709912142732316|0.001176843716919...|0.13753522440350205|[0.13753522440350...| 4|
//|138230919| 0.024| 0.10388031624658645|0.002493127589918075| 0.1303734438365045|[0.1303734438365045]| 4|
//| 13823083|0.022727272727272728| 0.11276067737901643|0.002562742667704919| 0.1380506927739941|[0.1380506927739941]| 4|
//| 13823431| 0.01639344262295082| 0.13461458465166434|0.002206796469699...|0.15321482374431458|[0.15321482374431...| 4|
//| 4034923|0.009259259259259259| 0.12882071966768546|0.001192784441367458|0.13927276336831218|[0.13927276336831...| 4|
//| 4033575| 0.032| 0.07938713328518321|0.002540388265125...|0.11392752155030907|[0.11392752155030...| 4|
![img](https://img-blog.csdnimg.cn/img_convert/aaa2d666bdbc1797635eac183de3195d.png)
![img](https://img-blog.csdnimg.cn/img_convert/afede4818f65aa7ec55763b8a38cba06.png)
![img](https://img-blog.csdnimg.cn/img_convert/bdfbf240d410f1e6719402a97e84f332.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**
|
[外链图片转存中...(img-MBP7OJbu-1715722353258)]
[外链图片转存中...(img-CP2zMAWs-1715722353258)]
[外链图片转存中...(img-0UdFkpxE-1715722353258)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**