Spark自带的交替最小二乘法(ALS) 推荐算法实践

前言:
先简单介绍一下常见的推荐算法:

Algorithmdescription
基于关系型规则的推荐
(Association Rule)
• 消费者购买产品A, 那么他有多大机会购买产品 B
• 购物车分析 啤酒和尿布)
基于内容的推荐
(Content-based)
• 分析网页内容自动分类,再将用户自动分类
• 将新进已分类的网页推荐给感兴趣的用户
人口统计式的推荐
(Demographic)
• 将用户以个人属性(性别,年龄,教育背景,居住地,语言) 作为分类指标
• 以此类作为推荐的基础
协同过滤式的推荐
(Collaborative Filtering)
• 通过观察所有用户对产品的评分来推断用户的喜好
• 找出对产品评分相近的其他用户,他们喜欢的产品当前用户多半也会喜欢

本篇博客即采用协同过滤算法来实现推荐
协同过滤算法主要有下面几个优缺点:

优点缺点
• 可以达到个性化推荐
• 不需要内容分析
• 可以发现用户新的兴趣点
• 自动化程度高
• 冷启动问题:如果没有历史数据就没法分析
• 新用户问题: 新用户没有评分,就不知道他的喜好

在实际的开发过程当中都是采用多种推荐算法协调处理的模式,这样才能实现互补,从而达到精准推荐的目的,博主这里使用python和spark来进行算法的实现,所以要预先搭建好spark环境,可以参照博主前面的文章进行配置,除了环境还要准备MovieLens的开源数据,博主这里采用的是100k的数据集,大家根据自己的机器配置进行选择;下面步入正题:

先导入一些必要的库

import pyspark
# 这个类的导入是次要的,可要可不要,主要是一个Rating类用于方便表示rating
from pyspark.mllib.recommendation import Rating
# 这个就是导入推荐算法中的交替最小二乘法库
from pyspark.mllib.recommendation import ALS

实例化一个spark的上下问对象

sc = pyspark.SparkContext(master='local[*]',appName="test1")

准备数据

从本地导入数据

raw_user_data = sc.textFile("file:/home/zh123/.jupyter/workspace/ml-100k/u.data")

查看导入的数据格式

raw_user_data.take(5)
['196\t242\t3\t881250949',
 '186\t302\t3\t891717742',
 '22\t377\t1\t878887116',
 '244\t51\t2\t880606923',
 '166\t346\t1\t886397596']

将每行数据先以"’\t"进行分片处理(只取前面三列 user, product, rating)

raw_ratings = raw_user_data.map(lambda line:line.split("\t")[:3])

查看一下分片后的数据格式

raw_ratings.take(5)
[['196', '242', '3'],
 ['186', '302', '3'],
 ['22', '377', '1'],
 ['244', '51', '2'],
 ['166', '346', '1']]

将每行数据够造为 Rating 对象 Rating(user,product,rating)

ratings_rdd = raw_ratings.map(lambda x:Rating(*x))

查看构造完成的数据格式

ratings_rdd.take(5)
[Rating(user=196, product=242, rating=3.0),
 Rating(user=186, product=302, rating=3.0),
 Rating(user=22, product=377, rating=1.0),
 Rating(user=244, product=51, rating=2.0),
 Rating(user=166, product=346, rating=1.0)]

初始化训练集中的用户个数

# 流程:投影出用户字段 -> 然后对用户字段去重 -> 统计用户的个数
user_count = ratings_rdd.map(lambda x:x.user).distinct().count()
user_count
943

初始化训练集中的产品个数

# 流程:投影出产品字段 -> 对产品进行去重 -> 统计产品数量
product_count = ratings_rdd.map(lambda x:x.product).distinct().count()
product_count
1682

开始训练模型

model = ALS.train(ratings_rdd,rank=10,iterations=10,lambda_=0.01)

模型为用户进行推荐产品

# recommendProducts参数含义 (user:用户id,num:需要为该用户推荐的产品数量)
model.recommendProducts(user=100,num=10)
[Rating(user=100, product=464, rating=6.328077627837865),
 Rating(user=100, product=1114, rating=6.0246494675621864),
 Rating(user=100, product=888, rating=5.957080472811217),
 Rating(user=100, product=776, rating=5.94518524812436),
 Rating(user=100, product=1456, rating=5.570928201780987),
 Rating(user=100, product=1153, rating=5.276014679950186),
 Rating(user=100, product=745, rating=5.273830915853978),
 Rating(user=100, product=309, rating=5.2226922589528755),
 Rating(user=100, product=1159, rating=5.214222938082385),
 Rating(user=100, product=967, rating=5.191467123059153)]

用模型为产品推荐用户

# recommendUsers 参数含义 (product:产品id,num:需要推荐的用户数量)
model.recommendUsers(product=101,num=10)
[Rating(user=575, product=101, rating=7.786829895272848),
 Rating(user=842, product=101, rating=7.385093317833681),
 Rating(user=777, product=101, rating=6.815955510387151),
 Rating(user=310, product=101, rating=6.749508509094776),
 Rating(user=752, product=101, rating=6.4059841032560945),
 Rating(user=745, product=101, rating=6.303744522941349),
 Rating(user=281, product=101, rating=6.268866937046303),
 Rating(user=51, product=101, rating=6.250170924530637),
 Rating(user=695, product=101, rating=6.158916996903442),
 Rating(user=649, product=101, rating=5.951955147976774)]

导入产品信息数据

product_data = sc.textFile("file:/home/zh123/.jupyter/workspace/ml-100k/u.item")

查看产品数据样例

product_data.take(5)
['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']

将每行产品数据根据 “|” 进行分割,然后取前两项

# 产品数据格式(product_id,product_name)
product_rdd = product_data.map(lambda line:line.split("|")).map(lambda x:(int(x[0]),x[1]))
product_rdd.take(5)
[(1, 'Toy Story (1995)'),
 (2, 'GoldenEye (1995)'),
 (3, 'Four Rooms (1995)'),
 (4, 'Get Shorty (1995)'),
 (5, 'Copycat (1995)')]

利用产品信息生成 id -> name的映射字典

product_id_to_name = product_rdd.collectAsMap()
list(product_id_to_name.items())[:5]
[(1, 'Toy Story (1995)'),
 (2, 'GoldenEye (1995)'),
 (3, 'Four Rooms (1995)'),
 (4, 'Get Shorty (1995)'),
 (5, 'Copycat (1995)')]

显示推荐的产品名称

for item in model.recommendProducts(user=100,num=10):
    print("为用户 {} 推荐 {}  推荐指数: {}".format(item.user,
                                          product_id_to_name[item.product],
                                          item.rating))
为用户 100 推荐 Vanya on 42nd Street (1994)  推荐指数: 6.328077627837865
为用户 100 推荐 Faithful (1996)  推荐指数: 6.0246494675621864
为用户 100 推荐 One Night Stand (1997)  推荐指数: 5.957080472811217
为用户 100 推荐 Three Wishes (1995)  推荐指数: 5.94518524812436
为用户 100 推荐 Beat the Devil (1954)  推荐指数: 5.570928201780987
为用户 100 推荐 Backbeat (1993)  推荐指数: 5.276014679950186
为用户 100 推荐 Ruling Class, The (1972)  推荐指数: 5.273830915853978
为用户 100 推荐 Deceiver (1997)  推荐指数: 5.2226922589528755
为用户 100 推荐 Stalker (1979)  推荐指数: 5.214222938082385
为用户 100 推荐 Little Lord Fauntleroy (1936)  推荐指数: 5.191467123059153

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值