大数据挖掘算法——时间衰变算法

2020-06-11 16:12:17 浏览数 (1)

小编说:时间衰变算法在很多行业都会被应用,就像电商行业,在给用户推荐商品时,会分析用户对于平台商品的兴趣偏好度,同时这个兴趣偏好度也会随着时间的流逝而发生变化。 本文选自《轻松学大数据挖掘:算法、场景与数据产品》

  • 1 何为时间衰变

大家或许都听过一个故事——“遗忘曲线”。

遗忘曲线是由德国心理学家艾宾浩斯(Hermann Ebbinghaus )研究发现的,其描述了人类大脑对新事物遗忘的规律,人们可以从遗忘曲线中掌握遗忘规律并加以利用,从而提升自我记忆的能力。

人的记忆衰变过程,如图1所示。

图1 人的记忆衰变过程(来自百度百科)

这条曲线告诉人们在学习中的遗忘是有规律的,遗忘的进程很快,并且先快后慢。在分析用户对电商平台琳琅满目的商品的兴趣偏好的变化时,也可以借鉴遗忘曲线。

  • 2 如何理解兴趣和偏好

对于兴趣和偏好这两个概念,从不同的角度分析会有不同的定义,这里从时间的角度分析。

兴趣:对事物喜好或关切的情绪,它是参与实践的基础,可以看作是一个短期行为。随着时间的推移,这种喜好也随之变化。

偏好:具有浓厚的积极情绪,伴随着成长过程中的主观倾向,可以看作是一个长期行为,它是基本稳定的。

对于电商平台来说,通过营销活动达到的目的是关心用户的“短期兴趣”。看看用户短期内会更倾向于购买哪些宝贝,从而更好地去做精准营销,如短信、站内广告等。

  • 3 时间衰变算法的抽象

最简单的场景,如果用户在半年前购买过某件商品,但从此以后没有再次对其产生过任何行为(浏览、收藏、加入购物车和购买),那么用户对于该商品的兴趣衰变曲线如图2所示。

图2 单次行为的衰变曲线

重复行为是指用户在半年内针对同一商品多次浏览、收藏、购买该商品。

令t1、t2、t3表示3次相邻重复行为的时刻,用户兴趣度的衰变曲线如图3所示。

图3 用户兴趣度的衰变曲线

  • 4 采用Spark实现模型

在分析用户的商品推荐时,我们会选择动手实践其中的熵权重算法和时间衰变算法,最终结合业务的实际场景重新组合一个综合模型。

1.数据源的获取

这里会考虑从HBase中读取数据源,具体数据特征会涉及用户ID、商品类目、宝贝、行为类型、次数和操作时间。Apache HBase经过长达8年的发展,在2017年1月中旬又发布了新版本(Hbase 1.3.0),多个方面的性能也得到了提升。

为了能够成功调用HBase的API,我们优先在Maven工程的pom.xml中添加如下代码。

代码语言:javascript复制
<dependency>        
   <groupId>org.apache.hbase</groupId>        
   <artifactId>hbase-client</artifactId>        
   <version>1.2.4</version></dependency>

注:这里使用的是Hbase 1.2.4版本,可以在中央仓库mvnrepository中搜索hbase-client来进行选择。

接下来给出一个连接HBase的测试版本,检测是否能够成功获取HBase中的表数据,代码如下。

代码语言:javascript复制
/**
 * 扫描rowkey返回行数
 *
 * @param prefixRowKey rowkey前缀
 * @return 行数
 */
def getRowPrefixNum(table: Table,prefixRowKey: String): Option[Int] = {
  var num = 1
  try {
      val scan: Scan = new Scan()
      scan.setStartRow(Bytes.toBytes(prefixRowKey))
      scan.setStopRow(Bytes.toBytes(prefixRowKey   "|"))
      val resultScanner: ResultScanner = table.getScanner(scan)
      val it = resultScanner.iterator()
       while (it.hasNext) {
        it.next()
        num  = 1
      }
 resultScanner.close()
 table.close()
 Some(num)
 } catch {
       case e: Exception => logger.error("统计行数出错,{}",e.getMessage)
      table.close()
      Some(1)
  }
}

main运行的代码模块,可以检测数据获取流程是否正常,代码如下。

代码语言:javascript复制
def main(args: Array[String]): Unit = {
      val conf = HBaseConfiguration.create()
       conf.set(HConstants.ZOOKEEPER_CLIENT_PORT, "端口号")
       conf.set(HConstants.ZOOKEEPER_QUORUM, "data1,data2,data3")
      val connection= ConnectionFactory.createConnection(conf)
      val table=connection.getTable(TableName.valueOf("t_user"))
      val s=getRowPrefixNum(table,"rowkey")
      println(s.getOrElse("0"))
}

最后补充整个工程相关的依赖包,代码如下。

代码语言:javascript复制
import org.slf4j.{Logger, LoggerFactory}
import org.apache.hadoop.hbase.{HBaseConfiguration, HConstants, TableName}
import org.apache.hadoop.hbase.client._
import org.apache.hadoop.hbase.util.Bytes

2.用户行为权重的调整

这里的数据输入来源于从HBase获取到的用户数据。优先选择用户行为的数据计算出5种行为(浏览、点击、收藏、加入购物车和购买)的权重值。

(1)确定算法过程中的统计指标,代码如下。

代码语言:javascript复制
val standDatas = rdd.map(_.split(SEPARATOR0)).map(record =>
 {
   var str = ""
   for(i <- 1 until record.length) {
    //其中round为方法调用,保留4位有效数字
     val standValue = round((record(i).toDouble 1)/
      (indexMap.get(i).get._1 indexMap.get(i).get._2),4)
      str = str.concat((standValue*math.log(standValue)).toString). concat(SEPARATOR0)
    }
     str.trim()
 }
).map(record =>
     {
      val arraySet = ArrayBuffer[Double]()
       for(i <- 0 until record.length) {
          arraySet =record(i).toDouble
      }
      arraySet
      }
)

其中涉及的统计指标都会在后期的计算中用到,需要缓存在RDD中。

(2)确定指标的熵值,代码如下。

代码语言:javascript复制
val resultSet = ArrayBuffer[Double]()
for(i <- 1 to featureNum) {
    val sumAndCount = standDatas.map(_.apply(i-1)).stats()
   val value=div(sumAndCount.sum,-math.log(sumAndCount.count),4)
   resultSet  = value
}

这步主要是计算每个特征向量的熵值大小,也是为计算最后的权重大小做准备的。

(3)确定特征向量的权重值,代码如下。

代码语言:javascript复制
//确定每个特征向量的权重值
val weightSet = ArrayBuffer[Double]()
for(i <- 0 until featureNum){
    weightSet =div(resultSet.apply(i),resultSet.sum,4)
}
weightSet.toArray

最终将计算出的用户行为权重单独保存在缓存Cache中,为了后期做兴趣衰变分析计算时可以再使用。

3.用户兴趣衰变的量化

结合上述的Hbase数据源和行为权重值,计算每个用户的兴趣衰变值,主要有以下两个步骤。

(1)计算用户兴趣衰变值,代码如下。

代码语言:javascript复制
/*
* @describe: 对兴趣衰变的计算
* @param: behav为行为集,factor为衰变因子,weightSet为权重集
*/
 def decayAlgorithm(behav:String,factor:Double,weightSet:Map [String,Double]):Double={
   val behavSet = behav.split("_")
   val behavCategory = behavSet.apply(0)
   val behavDiff = behavSet.apply(1).toDouble
   val behavNum = behavSet.apply(2).toDouble   val interestValue = math.exp(-factor * behavDiff)*behavNum
   behavCategory match {
      case "browse" => weightSet.get("browse").get*interestValue
      case "click" => weightSet.get("click").get*interestValue
      case "collect" => weightSet.get("collect").get*interestValue
      case "addCar" => weightSet.get("addCar").get*interestValue
      case "buy" => weightSet.get("buy").get*interestValue
   }
 }

在RDD中调用上述函数进行处理,计算用户兴趣随着时间的衰变。

(2)采用Sigmoid进行归一化处理,代码如下。

代码语言:javascript复制
/*
* @describe: 对兴趣衰变进行归一化处理
* @param: decayValue为衰变的兴趣度,factorsigmoid为归一化参数
*/
 def decayRate(decayValue:Double,factorsigmoid:Double):Double = {
   round(1.0/(1 math.exp(3.0-factorsigmoid*decayValue)),4)
 }

上述是对用户最终的兴趣值进行归一化的过程,得到用户对宝贝列表的兴趣排名,从而进行有针对性的推荐。和大家以往熟知的协同过滤推荐有所差异,基于用户兴趣偏好的衰变分析也可以做一定业务场景下的用户推荐。

数据化运营中的精准推荐涉及的业务场景很多,更多时候会从多面分析用户,甚至包括用户画像体系和商品画像体系。

0 人点赞