PySpark 创建搜索推荐

1、PySpark 创建搜索推荐

1.1、常见推荐算法

  • 常见推荐算法
算法说明
基于关系型规则的推荐(Association Rule)消费者购买产品A,那么他有多大机会购买产品B;<br> 购物车分析(啤酒和尿布)
基于内容的推荐(Context-based)分析网页内容自动分类,在将用户自动分类;<br> 将新进分类的网页推荐给对该群感兴趣的用户
人口统计式的推荐(Demographic)将用户以个人属性(性别、年龄、教育背景、居住地、语言)作为分类指标; <br> 以此类作为推荐标准
协同过滤式推荐(Collaborative Filtering)通过观察所有用户对产品的评分来推断用户的喜好; <br> 找出对产品评分相近的其他用户,他们喜欢的产品当前用户多半也会喜欢
  • 协同过滤式推荐(Collaborative Filtering)推荐的优缺点
有点缺点
可以达到个性化推荐;<br> 不需要内容分析;<br> 可以发现用户新的兴趣点; <br> 自动化程度高冷启动问题(Cold-start):如果没有历史数据就没有办法分析; <br> 新用户问题:新用户没有数据,就不知道他的喜好;

1.2、Spark MLlib ALS(Alternating Least Squares) 推荐算法

ALS(Alternating Least Squares) 推荐算法,交替最小二乘法。在机器学习中,特指使用最小二乘法的一种协同推荐算法;

网站上的设计经常会请用户对某个产品进行评分,如1-5分,可以整理如下图的矩阵;

  • 显示评分
用户ID项目1项目2项目3项目4项目5
user1215
user21311
user334
user42212
user511141

有些网站在设计可能并不会请用户进行评分,但是会记录用户是否选择了某个产品,如果用户选择了某个产品,就代表用户可能对该产品有兴趣,可用1表示,整理如下图的矩阵;

  • 隐式评分
用户ID项目1项目2项目3项目4项目5
user1111
user21111
user311
user41111
user511111

推荐算法就是要找出两个用户的相似性,如,user1有兴趣的项目为项目(1,2,3),user2有兴趣的项目为项目(1,2,3,4),user1比user2少了项目4;因此,当推荐算法要推荐项目给user1会推荐项目4;

  • 稀疏矩阵

当用户与项目评分越来越多时,会出现大部分都是空白(大部分项目没有评分),这种矩阵称为稀疏矩阵;当矩阵非常大的时候,要计算这样的矩阵,非常浪费资源和时间;

  • 矩阵分解

为了解决稀疏矩阵的问题,需要采用矩阵分解,将矩阵A(m X n)分解为X(m X rank)矩阵与Y(rank X n),如下图

PySpark 创建搜索推荐

1.3、ALS数据训练和推荐

1.3.1、数据准备

使用的数据主要有u.data(用户评分数据)和u.item(电影数据)

数据文件下载,如链接失效页面地址

$ head data/u.{data,item}
==> data/u.data <==
196 242 3   881250949
186 302 3   891717742
22  377 1   878887116
244 51  2   880606923
166 346 1   886397596
298 474 4   884182806
115 265 2   881171488
253 465 5   891628467
305 451 3   886324817
6   86  3   883603013

==> data/u.item <==
1|Toy Story (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Toy%20Story%20(1995)|0|0|0|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0
2|GoldenEye (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?GoldenEye%20(1995)|0|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0
3|Four Rooms (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Four%20Rooms%20(1995)|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0|0
4|Get Shorty (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Get%20Shorty%20(1995)|0|1|0|0|0|1|0|0|1|0|0|0|0|0|0|0|0|0|0
5|Copycat (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Copycat%20(1995)|0|0|0|0|0|0|1|0|1|0|0|0|0|0|0|0|1|0|0
6|Shanghai Triad (Yao a yao yao dao waipo qiao) (1995)|01-Jan-1995||http://us.imdb.com/Title?Yao+a+yao+yao+dao+waipo+qiao+(1995)|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0
7|Twelve Monkeys (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Twelve%20Monkeys%20(1995)|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|0|0
8|Babe (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Babe%20(1995)|0|0|0|0|1|1|0|0|1|0|0|0|0|0|0|0|0|0|0
9|Dead Man Walking (1995)|01-Jan-1995||http://us.imdb.com/M/title-exact?Dead%20Man%20Walking%20(1995)|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0
10|Richard III (1995)|22-Jan-1996||http://us.imdb.com/M/title-exact?Richard%20III%20(1995)|0|0|0|0|0|0|0|0|1|0|0|0|0|0|0|0|0|1|0
u.data包含4个字段:userid(用户id)、item id(项目id)、rating(评分)、timestamp(日期时间戳)
u.item有多个字段,在此取前两个:movie id(电影id)、movie title(电影片名)

1.3.2、程序思路

【u.data】 ——sc.textFile——> 【rawUserData】 ——map——> 【rawRatings】 ——map——> 【RatingsRDD】 ——ALS.train——> 【MatirixFactoization Model】

1.3.3、程序实现

  • 设置文件读取路径
In [1]: Path = "file:/home/hadoop/pyspark/PythonProject/recommend/"
  • 导入u.data数据,取前3个字段:用户id,产品id,评分
In [2]: rawUserData = sc.textFile(Path + "data/u.data")

In [3]: ratingsRDD = rawUserData.map(lambda line: line.split("\t")[:3] ).map(lambda x: (x[0],x[1],x[2]))
  • 导入ALS进行模型训练
In [4]: from pyspark.mllib.recommendation import ALS

In [5]: model = ALS.train(ratingsRDD, 10, 10, 0.01)
  • 导入电影数据u.item,取前两个字段:电影ID和电影名称
In [6]: itemRDD = sc.textFile(Path + "data/u.item")

In [7]: movieTitle = itemRDD.map(lambda line:line.split("|")).map(lambda a:(a[0],a[1])).collectAsMap()
  • 使用模型针对用户进行产品推荐,针对用户id:100,推荐5部影片
In [8]: recommendMovie = model.recommendProducts(100,5)

In [9]: for rdm in recommendMovie:
   ...:     print("针对用户ID: {0},推荐电影:{1} ,推荐评分:{2}".format(rdm[0], movieTitle.get(str(rdm[1])), rdm[2]))
   ...:         
针对用户ID: 100,推荐电影:Angel Baby (1995) ,推荐评分:7.610337473154874
针对用户ID: 100,推荐电影:Pather Panchali (1955) ,推荐评分:6.615085728728855
针对用户ID: 100,推荐电影:Once Were Warriors (1994) ,推荐评分:6.417519553465505
针对用户ID: 100,推荐电影:Radioland Murders (1994) ,推荐评分:6.24059727584324
针对用户ID: 100,推荐电影:Crooklyn (1994) ,推荐评分:5.944125863246919
  • 使用模型针对电影进行用户推荐,针对产品id:200,给5个用户推荐
In [10]: recommendUser = model.recommendUsers(200,5)

In [11]: for reu in recommendUser:
    ...:     print("针对用户ID: {0},推荐电影:{1} ,推荐评分:{2}".format(reu[0], movieTitle.get(str(reu[1])), reu[2]))
    ...:     
针对用户ID: 475,推荐电影:Shining, The (1980) ,推荐评分:7.06404094277568
针对用户ID: 762,推荐电影:Shining, The (1980) ,推荐评分:6.720699631364651
针对用户ID: 695,推荐电影:Shining, The (1980) ,推荐评分:6.221277830269441
针对用户ID: 810,推荐电影:Shining, The (1980) ,推荐评分:5.9598423486309535
针对用户ID: 917,推荐电影:Shining, The (1980) ,推荐评分:5.947701017469912

1.3.4、完整程序


#!/usr/bin/env python
# -*- coding:utf-8 -*-

"""
进行训练存储模型,以便给推荐阶段使用
1.数据读取:读取u.data,经过处理后产生评分数据ratingsRDD;
2.训练阶段:评分数据ratingsRDD经过ALS.train训练产生模型 Model;
3.存储模型:存储模型Model在本地或者HDFS,作为后续推荐使用。

载入模型进行推荐
1.数据读取:读取u.item,经过数据处理后产生movieTitle(电影ID/名称 的字典)
2.载入模型:载入recommendTrain.py 中的存储模型Model;
3.推荐阶段:使用模型Model 进行推荐,使用movieTitle转换显示推荐的电影名称
"""

from pyspark.mllib.recommendation import ALS, MatrixFactorizationModel
from pyspark import SparkConf, SparkContext
import time

def CreateSparkContext(appName):
    """创建spark context 对象"""
    conf = SparkConf().setAppName(appName).\
           set("spark.ui.showConsoleProgress", "false")
    sc = SparkContext(conf = conf)
    return sc

def PreUdata(sc, Pathdir, udata):
    """载入训练数据"""
    # 读取数据
    rawUserData = sc.textFile(Pathdir + udata)
    # 读取rawUserData 前3个字段,用户/产品/评价
    ratingsRDD = rawUserData.map(lambda line: line.split("\t")[:3]).\
                                  map(lambda x: (x[0],x[1],x[2]))
    return ratingsRDD

def SaveModel(sc, Pathdir, ModelName):
    """保存训练好的模型"""
    try:
        model.save(sc, Pathdir + ModelName)
    except Exception:
        print("模型已经存在,请先删除...")

def preUitem(sc, Pathdir, uitem):
    """载入用户推荐的数据"""
    print("开始读取电影ID与电影名称的字典...")
    itemRDD = sc.textFile(Pathdir + uitem)
    # 创建 电影ID 和 电影名称 的字典
    movieTitle = itemRDD.map(lambda line:line.split("|"))\
                 .map(lambda a:(float(a[0]),a[1]))\
                 .collectAsMap()
    return(movieTitle) 

def loadModel(sc, Pathdir, ModelName):
    """ 加载保存模型 """
    try:
        model = MatrixFactorizationModel.load(sc, Pathdir + ModelName)
    except Exception:
        print("找不到ALSModel模型,请先训练")
    return model

def RecommendMovies(model, movieTitle, userID):
    """根据电影推荐"""
    RecommendMovie = model.recommendProducts(userID, 10)
    print("针对用户ID" + str(userID) + "推荐下列相关电影:\n")
    for rdm in RecommendMovie:
        print("针对用户ID: {0},推荐电影:{1} ,推荐评分:{2}".\
             format(rdm[0], movieTitle.get(rdm[1]), rdm[2]))

def RecommendUsers(model, movieTitle, movieID):
    """根据用户推荐 """
    RecommendUser = model.recommendUsers(movieID, 10)
    print("针对电影ID: {0} 电影名:{1} 推荐给下列用户:\n".\
          format(movieID, movieTitle[movieID]))
    for rdu in RecommendUser:
        print("针对用户ID: {0},推荐电影:{1} ,推荐评分:{2}".\
              format(rdu[0], movieTitle.get(rdu[1]), rdu[2]))

if __name__ == "__main__":
    # 设置应用名,工作路径..
    appName = u"Recommend"
    Pathdir = u"file:/home/hadoop/pyspark/PythonProject/recommend/"
    udata = u"u.data"
    uitem = u"u.item"
    ModelName = u"ALSmodel"
    print("初始化环境,创建应用,名字:Recommend")
    sc = CreateSparkContext(appName)
    print("==========数据准备阶段===========")
    ratingsRDD = PreUdata(sc, Pathdir, udata)
    print("==========训练阶段===============")
    print("开始ALS训练,参数rank=5,iterations=10, lambda=0.01");
    model = ALS.train(ratingsRDD, 5, 10, 0.01)
    print("========== 存储Model============")
    SaveModel(sc, Pathdir, ModelName)

    # 停留5秒,开始执行推荐
    time.sleep(5)

    print("==========载入推荐数据==========")
    movieTitle = preUitem(sc, Pathdir, uitem)
    print("==========载入训练模型==========")
    model = loadModel(sc, Pathdir, ModelName)

    # 通过产品或者用户进行推荐
    print("...............用户推荐...............")
    movieID = 200
    RecommendUsers(model, movieTitle, movieID)
    print("...............电影推荐...............")
    userID = 200
    RecommendMovies(model, movieTitle, userID)
  • 程序运行
$ spark-submit recommend.py

1.4、总结

使用 ALS 模块对影片的评价数据进行训练,训练后产生 MatrixFactorizationModel模型进行推荐,分布是针对产品和用户的推荐;

转载于:https://blog.51cto.com/balich/2134500

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值