![24b6a7481815f87c2ca910e25b0b82c7.png](https://i-blog.csdnimg.cn/blog_migrate/276caa6aa1b9ade4435bada38daf5d59.jpeg)
说到推荐系统问题,其实就是一个数据挖掘问题。输入是用户信息、物品信息、交互信息,输出是每个用户对应若干物品的列表。常用的推荐方法几乎都是从协同过滤方向和分类器方向演变过来的,所做的工作也都是基于相似度计算(UserCF和ItemCF),基于分类方法(矩阵分解和一系列LTR算法)。这两天刚好翻到一篇CSDN的博客《推荐系统的初体验(关联规则,协同过滤)》,这里面就说:
从更接近本质的观点来看,这两种方法的出发点和逻辑思路也是截然不同的。一般地,关联规则被划分为动态推荐,而协同过滤则更多地被视为静态推荐。
所谓动态推荐,我的理解是:推荐的基础是且只是当前一次(最近一次)的购买或者点击。譬如我在网站上看了一个赵丽蓉老师的小品,系统就找到与这个小品相关的关联规则,然后根据这个规则向我进行推荐(例如赵丽蓉老师的另外一个小品="=)。而静态推荐则是在对用户进行了一定分析的基础上,建立了这个用户在一定时期内的偏好排序,然后在这段时期内持续地按照这个排序来进行推荐。
这种动态推荐的方式,实际上有点类似在我们处理时序问题时,下一刻的结果是依赖前面几次的输出结果计算得到的,而不是基于变量本身的属性分析得到的。所以,基于关联规则的推荐算法也就是一个非用户个性化的推荐方法。然而从推荐系统实践来看,如何权衡使用个性化和非个性化的推荐结果本身存在很大争议,我们在做线上视频推荐就有非常深刻的体会,在超大规模稀疏数据下,基于统计的热度排序往往比用户个性化方案指标高几个点,因为用户偏好计算会存在很大的偏差。
在离线数据集上,我们也简单实现了一个基础模型。我们在做《CIKM 2019 EComm AI:用户行为预测》的间隙,跑了一下Spark上的FPGrowth模型。当然,从结果来看用处不大,毕竟对于大部分稀疏数据是分析不出什么规则的。但是对于小部分交互频繁数据,我认为,关联规则生成的结果会有很大概率命中真实结果。
首先是初始化环境,我们采用scala语言,代码是在notebook上跑的,一方面是方便看效果,一方面是方便远程实时运行任务。
%%init_spark
launcher.num_executors = 3
launcher.executor_cores = 5
launcher.driver_memory = '30g'
launcher.executor_memory = '30g'
launcher.master = "yarn"
launcher.conf.set("spark.sql.catalogImplementation", "hive")
launcher.conf.set("hive.metastore.uris","thrift://dn1:9083")
launcher.conf.set("spark.sql.warehouse.dir", "hdfs:///apps/hive/warehouse")
launcher.conf.set("spark.sql.broadcastTimeout", "60000")
launcher.conf.set("spark.driver.maxResultSize", "10g")
launcher.conf.set("spark.rpc.message.maxSize", "1024")
加载相关库文件。
import org.apache.spark.sql.types._
import org.apache.spark.sql.SaveMode
import org.apache.spark.sql.functions._
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions
import org.apache.spark.sql.expressions.Window
import scala.io
读取数据并更具关联规则输入生成购物篮,即构造
var train = spark.sql("select * from train where date_time=20190811")
// train.printSchema
// |-- user_id: string (nullable = true)
// |-- item_id: string (nullable = true)
// |-- behavior_type: string (nullable = true)
// |-- date_time: integer (nullable = true)
train = train.select("user_id", "item_id").distinct()
train = train.groupBy("user_id").agg(collect_list(col("item_id")).as("item_ids"))
val dataset = train.select("item_ids").map(t => t.toString().split(",")).toDF("item_ids").cache()
接着调用FPGrowth,并训练模型,预测结果。
import org.apache.spark.ml.fpm.{ FPGrowth,FPGrowthModel }
val fpgrowth = new FPGrowth().setItemsCol("item_ids").setMinSupport(0.0003).setMinConfidence(0.0002)
val model = fpgrowth.fit(dataset)
这里面支持度和置信度参数设置比较头疼,因为数据太稀疏了,所以要设得非常小才能有效果。最后,对原数据集进行预测。
model.transform(dataset).show()
![5055f19721bff7b9b0aface9562f759a.png](https://i-blog.csdnimg.cn/blog_migrate/5a9d537bee7587c09ef9d43660766620.jpeg)
结果非常惨目忍睹,但是我认为这部分的结果仍是有价值的,它可以作为个性化推荐结果的补充—对于某些计算得到的特别低评分却仍在推荐列表内的物品,可以由关联规则或热度排行榜计算的非个性化结果进行替代。
另外,推荐系统内还有一类重要的问题是搭配推荐问题,通过关联规则算法可以从数据表象得到表示搭配的规则,进行比较浅显的搭配推荐,更深层次的考虑我觉得需要从图结构或者知识图谱方向入手。
在去年PaperWeekly上解读Recsys2018的文章中,就指出搭配推荐一直是推荐系统中十分重要的问题,正如微博上的某个笑话:
“个人觉得现在的数据挖掘做的很烂,我在网上买了一个锅,结果下面推荐的都是锅,同志,我已经买了一个了还这么迫切的想买第二个么?”