Spark MLib支持ALS推荐算法,通过观察所有用户给产品的评价来推断每个用户的喜好,并向用户推荐适合的多个产品,也可以把某一个产品推荐给多个用户。

推荐算法介绍

基于关系型规则的推荐(Association Rule)

消费者购买产品A,那么他有多大机会购买产品B。

基于内容的推荐(Content-based)

分析网页内容自动分类,再将用户自动分类,将新进已分类的网页推荐给对该网页感兴趣的用户

人口统计式的推荐(Demographic)

将用户以个人属性(性别、年龄、教育背景、居住地、语言)作为分类的指标,以此作为推荐的基础

协同过滤式的推荐(Collaborative Filtering)

通过观察所有用户对产品的评分来判断用户的喜好,找出对产品评分相近的其他用户,他们喜好的产品当前用户多半也喜欢

协同过滤的优缺点

优点:可以达到个性化推荐,不需要内容分析,可以发现用户兴趣点,自动化程度高

缺点:冷启动问题,即没有历史数据就没有办法分析;新用户问题,即没有评分,就不知道喜好

ALS推荐算法介绍

Spark MLib支持的ALS推荐算法是机器学习的协同过滤算法。根据用户的评分来推断每个用户的喜好,并进行推荐。

评分

显式评分:用户直接对产品的评分
隐式评分:根据用户选择的产品记录,但不知道评分等级

稀疏矩阵(Sparse Matrix)问题

当用户与产品评分成千上万时,矩阵会很大,而且很多会是空白的,使用计算机处理这样的矩阵会很浪费内存,且花费很多时间。

spark任务报错atlas类找不到 spark alias_hadoop

矩阵分解

解决稀疏矩阵问题,需要采用矩阵分解

spark任务报错atlas类找不到 spark alias_spark_02

准备数据

数据集可以用MovieLens网站的数据集来进行训练
网址:https://grouplens.org/datasets/movielens/ 我这里选用ml-100k(4.7M)

wget http://files.grouplens.org/datasets/movielens/ml-100k.zip

解压

unzip -j ml-100k.zip

spark任务报错atlas类找不到 spark alias_spark任务报错atlas类找不到_03


u.data文件

用户评分数据,包括user id、item id、rating、timestamp四个字段

u.item文件
电影数据

文件上传到hadoop集群

hadoop fs -put ../data /user/hduser/movie

以YARN模式启动pyspark

HADOOP_CONF_DIR=/usr/local/hadoop/etc/hadoop pyspark --master yarn --deploy-mode client

训练数据

读取数据

rawUD = sc.textFile("hdfs://master:9000/user/hduser/movie/data/u.data")

spark任务报错atlas类找不到 spark alias_spark任务报错atlas类找不到_04

导包
from pyspark.mllib.recommendation import Rating

注:这里需要提前安装numpy,安装方法:
1、根据自己软件版本到这里下载whl包https://pypi.org/project/numpy/1.14.2/#files
2、传入linux的文件夹,pip install 即可

读取前3个字段
rawRatings = rawUD.map(lambda line:line.split("\t")[:3])

spark任务报错atlas类找不到 spark alias_ALS_05

ratingsRDD = rawRatings.map(lambda x:(x[0],x[1],x[2]))

x[0]:用户
x[1]:产品
x[2]:用户对此的评价

查看不重复的数据
numUsers = ratingsRDD.map(lambda x:x[0]).distinct().count()

spark任务报错atlas类找不到 spark alias_spark_06

训练模型

spark任务报错atlas类找不到 spark alias_spark任务报错atlas类找不到_07

导包
from pyspark.mllib.recommendation import ALS
ALS.train

显式评分(Explicit Rating)训练
ALS.tarin(ratings,rank,iterations=5,lamda_=0.01)

model = ALS.train(ratingsRDD, 10, 10, 0.01)

注:如果出现没有numpy异常,就检查下每个服务器是否安装numpy

隐式评分(Implicit Rating)训练

ALS.tarinImplicit(ratings,rank,iterations=5,lamda_=0.01)

spark任务报错atlas类找不到 spark alias_spark_08


spark任务报错atlas类找不到 spark alias_ALS_09


返回对象

spark任务报错atlas类找不到 spark alias_hadoop_10

利用模型进行推荐

model.recommendProducts(user:Int, num:Int)

spark任务报错atlas类找不到 spark alias_hadoop_11

针对用户进行推荐

针对用户100,推荐最有可能喜欢的前五个电影

model.recommendProducts(user=100, num=5)

spark任务报错atlas类找不到 spark alias_Spark 推荐算法_12

查看针对用户100推荐产品的评分

model.predict(100, 1311)
针对电影进行推荐用户

针对电影200推荐最有可能喜欢的前5个用户

model.recommendUsers(200,5)

spark任务报错atlas类找不到 spark alias_hadoop_13

显示电影名称
导入item
itemRDD = sc.textFile("hdfs://master:9000/user/hduser/movie/data/u.item")

spark任务报错atlas类找不到 spark alias_ALS_14

创建ID-电影名字典
movieTitle = itemRDD.map(lambda line:line.split("|")).map(lambda a:(float(a[0]),a[1])).collectAsMap()

spark任务报错atlas类找不到 spark alias_spark_15

开始推荐
recommendP = model.recommendProducts(100,5)
for p in recommendP:
	print("user:"+str(p[0])+","+"recommended:"+str(movieTitle[p[1]])+","+"rating:"+str(p[2]))

spark任务报错atlas类找不到 spark alias_ALS_16

综上,构建推荐系统程序

需要构建的两个程序

spark任务报错atlas类找不到 spark alias_hadoop_17


推荐系统示意图

spark任务报错atlas类找不到 spark alias_spark_18


RecommendTrain代码

#!/usr/bin/env python3
# coding=utf-8
# __author__: Alexander
from pyspark import SparkContext
from pyspark import SparkConf
from pyspark.mllib.recommendation import ALS

def CreateSparkContext():
    sparkConf = SparkConf() \
                .setAppName("RecommendTrain") \
                .set("spark.ui.showConsoleProgress", "false") \

    sc = SparkContext(conf = sparkConf)
    print("master="+sc.master)
    SetLogger(sc)
    SetPath(sc)
    return sc

def SetLogger(sc):
    logger = sc._jvm.org.apache.log4j
    logger.LogManager.getLogger("org").setLevel(logger.Level.ERROR)
    logger.LogManager.getLogger("akka").setLevel(logger.Level.ERROR)
    logger.LogManager.getRootLogger().setLevel(logger.Level.ERROR)

def SetPath(sc):
    global Path
    if sc.master[0:5] == "local":
        Path = "file:/root/pythonwork/movie/"
    else:
        Path = "hdfs://master:9000/user/hduser/"

def SaveModel(sc):
    try:
        model.save(sc, Path+"movie/ALSmodel")
        print("Model is saved")
    except:
        print("Error,Model is already exist")


def PrepareData(sc):
    file = sc.textFile(Path + "movie/data/u.data")
    rawRatings = file.map(lambda line: line.split("\t")[:3])
    ratingsRDD = rawRatings.map(lambda x: (x[0], x[1], x[2]))
    return ratingsRDD

if __name__ == "__main__":
    sc = CreateSparkContext()
    print("-----------Preparing----------")
    ratingsRDD = PrepareData(sc)
    print("-----------Training-----------")
    print("Start ALS training, rank=5,iterations=20, lambda=0.1")
    model = ALS.train(ratingsRDD, 5, 20, 0.1)
    print("-----------Saving Model-----------")
    SaveModel(sc)

运行

HADOOP_CONF_DIR=/usr/local/hadoop/etc/hadoop spark-submit --driver-memory 512m --executor-cores 2 --master yarn --deploy-mode client RecommendTrain.py

Recommend代码
代码

#!/usr/bin/env python3
# coding=utf-8
# __author__: Alexander
from pyspark.mllib.recommendation import MatrixFactorizationModel
from pyspark import SparkContext
from pyspark import SparkConf
import sys


def CreateSparkContext():
    sparkConf = SparkConf() \
                .setAppName("Recommend") \
                .set("spark.ui.showConsoleProgress", "false") \

    sc = SparkContext(conf=sparkConf)
    print("master="+sc.master)
    SetLogger(sc)
    SetPath(sc)
    return sc


def SetLogger(sc):
    logger = sc._jvm.org.apache.log4j
    logger.LogManager.getLogger("org").setLevel(logger.Level.ERROR)
    logger.LogManager.getLogger("akka").setLevel(logger.Level.ERROR)
    logger.LogManager.getRootLogger().setLevel(logger.Level.ERROR)


def SetPath(sc):
    global Path
    if sc.master[0:5] == "local":
        Path = "file:/root/pythonwork/"
    else:
        Path = "hdfs://master:9000/user/alex/"


def PrepareData(sc):
    print("Loading Data......")
    itemRDD = sc.textFile(Path+"movie/data/u.item")
    movieTitle = itemRDD.map(lambda line: line.split("|"))\
        .map(lambda a: (float(a[0]), a[1]))\
        .collectAsMap()
    return movieTitle

def Recommend(model):
    if sys.argv[1] == "--U":
        RecommendMovies(model, movieTitle, int(sys.argv[2]))
    if sys.argv[1] == "--M":
        RecommendUsers(model, movieTitle, int(sys.argv[2]))


def RecommendMovies(model, movieTitle, inputUserID):
    RecommendMovie = model.recommendProducts(inputUserID, 10)
    print("User ID:" + str(inputUserID))
    for i in RecommendMovie:
        print("user {0},movie {1},rating {2}"
              .format(i[0], movieTitle[i[1]], i[2]))


def RecommendUsers(model, inputMovieID):
    RecommendUser = model.recommendUsers(inputMovieID, 10)
    print("Movie ID:" + str(inputMovieID))
    for i in RecommendUser:
        print("user {0}, rating {2}"
              .format(i[0], i[2]))


def loadModel(sc):
    try:
        model = MatrixFactorizationModel.load(sc, Path+"movie/ALSmodel")
        print("Loading ALS Model.....")
    except:
        print("Error,ALS Model is not found!")
    return model

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Please input 2 parameter")
        exit(-1)
    sc = CreateSparkContext()
    print("-----------Preparing----------")
    movieTitle = PrepareData(sc)
    print("-----------Training-----------")
    print("Loading Model")
    model = loadModel(sc)
    print("-----------Recommend-----------")
    Recommend(model)

运行

HADOOP_CONF_DIR=/usr/local/hadoop/etc/hadoop spark-submit --driver-memory 512m --executor-cores 2 --master yarn --deploy-mode client Recommend.py --U 100

注:运行时其实传递了三个参数:
sys.argv[0]=‘Recommend.py’,也就是代码程序路径
sys.argv[1]=’–U’,代表执行对用户推荐电影
sys.argv[2]=‘100’,代表要推荐的用户ID

运行结果:

spark任务报错atlas类找不到 spark alias_spark_19