- 實驗介紹
通過在阿里雲天池上獲取關於圖書書本的數據集,核心是圍繞協同過濾算法進行推薦,主要是完成以下目標:
查詢功能:基於圖書名實現模糊查詢和准確查詢,基於評分和作者名進行准確查詢。
統計功能:基於圖書的平均評分、讀者對於某書的平均評分和用戶評論數作為依據,進行相關統計。
推薦功能:基於mapreduce和協同過濾算法,對某用戶進行圖書推薦。
- 實驗框架
- 流程設計
- 查詢功能
- 統計功能
- 推薦功能
- 關鍵代碼
- 查詢功能:主要是基於hive來進行查詢,主要是用sql語句來進行查詢功能,如模糊查詢書名;
先連接hive,然后編寫sql語句進行相關查詢,最后用impala庫中自帶的as_pandas函數進行相關展示。
-
1. if st.sidebar.button("模糊查詢圖書"): 2. sizee=0 3. if bookn=="": 4. st.info('請輸入查詢書名!') 5. else: 6. sql='''''select * from book1 where name like '''+'\''+str(bookn)+'%'+'\''+' limit 10' 7. cursor.execute(sql) 8. a=as_pandas(cursor) 9. 10. b=np.mat(a) 11. result=b.tolist() 12. if len(result)==0: 13. st.info('抱歉,未查詢到對應書目。') 14. else: 15. 16. st.dataframe(a)
- 統計功能:這塊主要是用mysql進行查詢,然后用pyecharts畫相關表進行展示。
-
1. if st.sidebar.button("用戶活躍度"): 2. 3. sql = '''''select userid ,count(*) from rate1 group by userid order by count(*) desc limit 10''' 4. sqlcursor.execute(sql) 5. users = sqlcursor.fetchall() 6. users 7. user=[] 8. num=[] 9. for u in users: 10. user.append(u[0]) 11. num.append(u[1]) 12. bar=Bar() 13. bar.add_xaxis(user) 14. bar.add_yaxis('用戶活躍度', num) 15. 16. streamlit_echarts.st_pyecharts(bar)
- 推薦功能:
本實驗中的圖書推薦系統是基於用戶的協同過濾算法實現的:主要分為3個Mapreduce步驟:
第一步:根據用戶評分數據集得到用戶-評分矩陣:
Map操作:key=user_id;values=[書名, 評分]
Reduce操作:key=user_id;values=[閱讀量,總評分,[書名, 評分],[ 書名, 評分]]
-
1. class Step1(MRJob): 2. def map_user(self, key, line): 3. user_id, item_name, rating = line.split('^') # 將原數據划分 4. yield user_id, (item_name, float(rating)) # map結果 user_id, [書名, 評分] 5. 6. def reduce_item(self, user_id, values): 7. item_count = 0 # 用戶讀過的圖書總數 后續計算用戶相似度需要 8. item_sum = 0 # 所有評分總和 9. final = [] 10. for item_name, rating in values: 11. item_count += 1 12. item_sum += rating 13. final.append((item_name, rating)) # reduce書名和評分 14. yield user_id, (item_count, item_sum, final) # user_id, [count, sum, ratings] 15. 16. def steps(self): 17. return [MRStep(mapper=self.map_user, 18. reducer=self.reduce_item),]
第二步:以第一步得到的用戶-評分矩陣作為輸入,尋找讀過某圖書的用戶列表;考慮到數據節點的性能,為了便於計算,將上一步的結果篩選,使用閱讀量在[300, 500]的用戶數據;
Map操作:key=圖書名;values=[user_id,閱讀量]
Reduce操作:key=圖書名;values=[[user_id1,閱讀量1]…… [user_idn,閱讀量n]]。
-
1. class Step2(MRJob): 2. # map輸出的key:圖書名, value:用戶,閱讀量 3. def map_item(self, id, line): 4. strr = line.split('\t', 1) # 划分一次 5. user_id = eval(strr[0]) 6. values = eval(strr[1]) 7. item_count, item_sum, ratings = values 8. for item in ratings: 9. yield item[0], (user_id, item_count) 10. 11. # 得到book user_list 12. def reduce_user(self, item, values): 13. user_list = [] 14. for user in values: 15. user_list.append(user) 16. yield item, (user_list) 17. 18. def steps(self): 19. return [MRStep(mapper=self.map_item, 20. reducer=self.reduce_user), ]
第三步:以上一步得到的圖書用戶列表作為輸入文件,計算用戶之間的相似度;
Map操作:key=[用戶id1,用戶id2];values=[id1閱讀量,id2閱讀量]
Reduce操作:key=[用戶id1,用戶id2];values=[相似度,共同圖書閱讀量]
-
1. class Step3(MRJob): 2. def pair_users(self, user_id, line): 3. values = eval(line.split('\t')[1]) 4. for user1, user2 in combinations(values, 2): 5. yield (user1[0], user2[0]), (user1[1], user2[1]) 6. # user1[0]是用戶名,user1[1]是用戶閱讀量 7. 8. def cal_similarity(self, users, counts): 9. num = 0 # num表示兩人共同讀過的圖書數量 10. user_pair, count = users, counts # count是用戶1和用戶2的閱讀量 11. user1, user2 = user_pair 12. cnt1 = 0 13. cnt2 = 0 14. for c1, c2 in count: 15. num += 1 # 當兩個key相同時,num++,表示共同圖書加一 16. cnt1 = c1 17. cnt2 = c2 18. fenmu = cnt1 + cnt2 -num 19. similarity = float(num / fenmu) 20. yield (user1, user2), (similarity, num)
- 查詢功能:主要是基於hive來進行查詢,主要是用sql語句來進行查詢功能,如模糊查詢書名;
- 結果展示
- 查詢功能:根據書名進行模糊查詢和准確查詢;查詢評分、查詢作者。
- 統計功能:用戶活躍度、最受歡迎圖書等
- 推薦功能:
考慮到有的用戶讀的書本很少,相比之下無法進行准確推薦,對於這部分用戶進行推薦查詢時會提醒用戶去查看相關榜單;
- 該圖書推薦系統的關鍵在於
- 推薦算法的實現,使用了基於用戶的協同過濾算法,利用三次mapreduce操作實現算法;
- 將數據存放至hdfs,使用Hadoop分布式平台。