基於使用者的電視節目推薦演算法例項
阿新 • • 發佈:2018-11-04
# -*- coding: utf-8 -*- """ Created on Thu Nov 1 10:29:52 2018 @author: AZ """ # 程式碼說明: # 基於使用者的協同過濾演算法的具體實現 import math import numpy as np import pandas as pd import os os.chdir('E:/廣電大資料營銷推薦專案案例/資料清洗/電視節目資訊資料預處理') # 藉助pearson相關係數進行修正後的餘弦相似度計算公式,計算兩個使用者之間的相似度 # 記 sim(user1, user2) = sigma_xy /sqrt(sigma_x * sigma_y) # user1和user2都表示為[[節目名稱,隱性評分], [節目名稱,隱性評分]],如user1 = [['節目一', 3.2], ['節目四', 0.2], ['節目八', 6.5], ...] def calCosDistByPearson(user1, user2): x = 0.0 y = 0.0 sigma_xy = 0.0 sigma_x = 0.0 sigma_y = 0.0 for item in user1: x += item[1] # user1對其看過的所有節目的平均評分 average_x = x / len(user1) for item in user2: y += item[1] # user2對其看過的所有節目的平均評分 average_y = y / len(user2) for item1 in user1: for item2 in user2: if item1[0] == item2[0]: # 對user1和user2都共同看過的節目才考慮進去 sigma_xy += (item1[1] - average_x) * (item2[1] - average_y) sigma_x += (item1[1] - average_x) * (item1[1] - average_x) sigma_y += (item2[1] - average_y) * (item2[1] - average_y) if sigma_x == 0.0 or sigma_y == 0.0: # 若分母為0,相似度為0 return 0 return sigma_xy/math.sqrt(sigma_x * sigma_y) # 建立所有使用者的觀看資訊(包含隱性評分資訊),“從使用者到節目” # 格式例子:users_to_items = {使用者一:[['節目一', 3.2], ['節目四', 0.2], ['節目八', 6.5]], 使用者二: ... } def createUsersDict(df): (m, n) = df.shape data_array = np.array(df.iloc[:m + 1, 1:]) users_names = np.array(df.iloc[:m + 1, 0]).tolist() items_names = np.array(df.columns)[1:] users_to_items = {} for i in range(len(users_names)): user_and_scores_list = [] for j in range(len(items_names)): if data_array[i][j] > 0: user_and_scores_list.append([items_names[j], data_array[i][j]]) users_to_items[users_names[i]] = user_and_scores_list return users_to_items # 建立所有節目被哪些使用者觀看的字典,也就是建立“從節目到使用者”的倒排表items_and_users # items_to_users = {節目一: [使用者一, 使用者三], 節目二: ... } def createItemsDict(df): (m, n) = df.shape data_array = np.array(df.iloc[:m + 1, 1:]) users_names = np.array(df.iloc[:m + 1, 0]).tolist() items_names = np.array(df.columns)[1:] items_to_users = {} for i in range(len(items_names)): users_list = [] for j in range(len(users_names)): if data_array[j][i] > 0: users_list.append(users_names[j]) items_to_users[items_names[i]] = users_list return items_to_users # 找出與使用者user_name相關的所有使用者(即鄰居)並依照相似度排序 # neighbors_distance = [[使用者名稱, 相似度大小], [...], ...] = [['使用者四', 0.78],[...], ...] def findSimilarUsers(users_dict, items_dict, user_name): neighbors = [] # neighbors表示與該使用者看過相同節目的所有使用者 for items in users_dict[user_name]: for neighbor in items_dict[items[0]]: if neighbor != user_name and neighbor not in neighbors: neighbors.append(neighbor) # 計算該使用者與其所有鄰居的相似度並降序排序 neighbors_distance = [] for neighbor in neighbors: distance = calCosDistByPearson(users_dict[user_name], users_dict[neighbor]) neighbors_distance.append([neighbor, distance]) neighbors_distance.sort(key=lambda item: item[1], reverse=True) return neighbors_distance # 基於使用者的協同過濾演算法 # K為鄰居個數,是一個重要引數,引數調優時使用 def userCF(user_name, users_dict, items_dict, K, all_items_names_to_be_recommend): # recommend_items = {節目名:某個看過該節目的該使用者user_name的鄰居與該使用者的相似度, ...} recommend_items = {} # 將上面的recommend_items轉換成列表形式並排序為recommend_items_sorted = [[節目一, 該使用者對節目一的感興趣程度],[...], ...] recommend_items_sorted = [] # 使用者user_name看過的節目 items_user_saw = [] for item in users_dict[user_name]: items_user_saw.append(item[0]) # 找出與該使用者相似度最大的K個使用者(鄰居) similar_users = findSimilarUsers(users_dict, items_dict, user_name) if len(similar_users) < K: k_similar_user = similar_users else: k_similar_user = similar_users[:K] # 得出對該使用者的推薦節目集 for user in k_similar_user: for item in users_dict[user[0]]: # 該使用者user_name沒有看過的節目才新增進來,才可以推薦給該使用者 if item[0] not in items_user_saw: # 而且該節目必須是在備選推薦節目集中 if item[0] in all_items_names_to_be_recommend: if item[0] not in recommend_items: # recommend_items是一個字典。第一次迭代中,表示將第一個鄰居使用者與該使用者的相似度加到節目名上,後續迭代如果有其他鄰居使用者也看過該節目, # 也將其與該使用者的相似度加到節目名上,迭代的結果就是該使用者對該節目的感興趣程度 recommend_items[item[0]] = user[1] else: # 如果某個節目有k個鄰居使用者看過,則將這k個鄰居使用者與該使用者的相似度相加,得到該使用者對某個節目的感興趣程度 recommend_items[item[0]] += user[1] for key in recommend_items: recommend_items_sorted.append([key, recommend_items[key]]) # 對推薦節目集按使用者感興趣程度降序排序 recommend_items_sorted.sort(key=lambda item: item[1], reverse=True) return recommend_items_sorted # 輸出推薦給該使用者的節目列表 # max_num:最多輸出的推薦節目數 def printRecommendItems(recommend_items_sorted, max_num): count = 0 for item, degree in recommend_items_sorted: print("節目名:%s, 推薦指數:%f" % (item, degree)) count += 1 if count == max_num: break # 主程式 if __name__ == '__main__': # all_users_names = ['A','B','C'] all_users_names = [3,13,23] df1 = pd.read_csv('./wordsbag/dataprocess/data/week/mydata/temp_movies_01mat.csv',sep=',',encoding='gbk',header='infer',error_bad_lines=False) (m1, n1) = df1.shape # 按照"備選推薦節目集及所屬型別01矩陣"的列序排列的所有使用者觀看過的節目名稱 items_to_be_recommended_names = np.array(df1.iloc[:m1 + 1, 0]).tolist() df2 = pd.read_csv('./wordsbag/dataprocess/data/week/mydata/temp_user_scores_mat2.csv',sep=',',encoding='gbk',header='infer',error_bad_lines=False) # users_dict = {使用者一:[['節目一', 3.2], ['節目四', 0.2], ['節目八', 6.5]], 使用者二: ... } users_dict = createUsersDict(df2) # items_dict = {節目一: [使用者一, 使用者三], 節目二: [...], ... } items_dict = createItemsDict(df2) for user in all_users_names: print("為使用者id為 %s 的推薦節目如下:" % user) recommend_items = userCF(user, users_dict, items_dict, 2, items_to_be_recommended_names) printRecommendItems(recommend_items, 5) print('該使用者的推薦任務完成。') print()
資料下載地址:https://download.csdn.net/download/qq_38281438/10757266