PYTHON_SPARK 基于物品协通过滤推荐算法离线化实现
本文主要内容
- 算法介绍
- spark介绍
- 算法实现的基本流程
- 代码分部详解
- 完整代码
1. 算法介绍
Wij表示标号i.j物品的相似度。
U(i,j)表示同时对i,j有评分的用户集合
2 . spark介绍
spark算子大致分为两类
1 Transformation 变换/转换算子,这种算子并不提交作业,完成作业过程中间转换处理。
Transformation操作是延迟计算的,也就是说从一个RDD生成转换生成另一个RDD转换操作不是马上执行,需要等到有action操作时才会真正触发运算。
2 Action 行动算子:这类算子会出发SparkContext提交Job 作业。
Action 算子会触发 Spark 提交作业(Job),并将数据输出 Spark系统。
本文中使用到的算子
Transformation 类算子:
(1) map
通过对这个RDD的每个元素应用一个人函数返回一个新的RDD
(2)flatmap
将结果扁平化,从而返回一个新的RDD
(3)reduceByKey
与groupByKey类似,却有不同。如(a,1), (a,2), (b,1), (b,2)。groupByKey产生中间结果为( (a,1), (a,2) ), ( (b,1), (b,2) )。而reduceByKey为(a,3), (b,3)。
reduceByKey 功能是聚合,groupByKey是分组
Action 类算子:
(1)groupByKey 将所有的数据划分入新的分区,在进行计算。若一个键对应的值太多,会导致内存溢出。
3 . 算法实现的基本流程
输入:user_id,item_id,rating
输出:item 对 item 的评分
(1)按商品分组,统计用户对商品的评分
(2)对评分进行归一化
(3)对所有的评分求和,得到item 对item的评分
4.代码分部详解
(1)对数据进行整理,用户对相同item评分的划分为一组
ResultRDD = rdd.map(lambda x:(x['item_id'],x['user_id'] + '+' + str(x['scope'])))
UserItem = ResultRDD.groupByKey().map(lambda x:(x[0],list(x[1])))
输出:
[(u’9428’,
[u’237472+5’,
u’199815+5’,
u’170943+5’,
…]),
(u’10299’,
[u’680727+3’,
u’2155030+2’,
u’436492+3’]))]
(2)对评分进行归一化处理,限制数据的取值范围,保证数据的准确性,可参考性
def guiyi(data):
item = data[0]
user_items = data[1]
sum = 0.0
user_score_list = []
for user_item in user_items:
user,s = user_item.split("+")
sum += pow(int(s), 2)
sum = math.sqrt(sum)
for user_item in user_items:
user,s = user_item.split("+")
user_score_list.append((user, item + "+" + str(float(s) / sum)))
return user_score_list
def fl(data):
return data
UserItemGy = UserItem.map(guiyi).flatMap(fl).groupByKey().map(lambda x:(x[0],list(x[1])))
输出:关于user 对 item 评分的集合
[(u’1308915’,
[u’9939+0.3194382825’,
u’10016+0.157407137505’,
u’10122+0.3194382825’,
u’10157+0.143149583578’,
…]),
(u’480835’,
[u’10344+0.316227766017’,
u’9535+0.105245666994’,
u’9614+0.490290337845’,
…])]
(3) 得出物品对物品的评分,两两取对,相加得出分数
def pair(data):
user = data [0]
item_score_list = data[1]
items = []
for i in range(0, len(item_score_list) - 1):
for j in range(i + 1, len(item_score_list)):
item_a, score_a = item_score_list[i].split("+")
item_b, score_b = item_score_list[j].split("+")
score = float(score_a) * float(score_b)
items.append((item_a + " + " + item_b , score))
items.append((item_b + " + " + item_a , score))
return items
UserItemSum = UserItemGy.map(pair).flatMap(fl).reduceByKey(lambda a, b: a + b)
输出:物品对物品的评分
[(u’10242 + 10309’, 0.04500002249999824),
(u’9657 + 9523’, 0.09382332812997889),
(u’9756 + 10259’, 0.012972730388020742)]
5. 完整代码
def fl(data):
return data
def guiyi(data):
item = data[0]
user_items = data[1]
sum = 0.0
user_score_list = []
for user_item in user_items:
user,s = user_item.split("+")
sum += pow(int(s), 2)
sum = math.sqrt(sum)
for user_item in user_items:
user,s = user_item.split("+")
user_score_list.append((user, item + "+" + str(float(s) / sum)))
return user_score_list
def pair(data):
user = data [0]
item_score_list = data[1]
items = []
for i in range(0, len(item_score_list) - 1):
for j in range(i + 1, len(item_score_list)):
item_a, score_a = item_score_list[i].split("+")
item_b, score_b = item_score_list[j].split("+")
score = float(score_a) * float(score_b)
items.append((item_a + " + " + item_b , score))
items.append((item_b + " + " + item_a , score))
return items
ResultRDD = rdd.map(lambda x:(x['item_id'],x['user_id'] + '+' + str(x['scope'])))
UserItem = ResultRDD.groupByKey().map(lambda x:(x[0],list(x[1])))
UserItemGy = UserItem.map(guiyi).flatMap(fl).groupByKey().map(lambda x:(x[0],list(x[1])))
UserItemSum = UserItemGy.map(pair).flatMap(fl).reduceByKey(lambda a, b: a + b)