基於內容的推薦演算法的實現程式碼例項
阿新 • • 發佈:2018-11-04
本次例項需要三個資料檔案
分別為節目及其所屬標籤型別的01矩陣;使用者--節目評分矩陣;使用者收視了的節目--標籤01矩陣。
可以直接下載下來使用https://download.csdn.net/download/qq_38281438/10757266
具體程式碼如下:
# -*- coding: utf-8 -*- """ Created on Thu Nov 1 09:33:14 2018 @author: AZ """ import math import pandas as pd import numpy as np import os os.chdir('E:/廣電大資料營銷推薦專案案例/資料清洗/電視節目資訊資料預處理') # 建立節目畫像 # 引數說明: # items_profiles = {item1:{'label1':1, 'label2': 0, 'label3': 0, ...}, item2:{...}...} def createItemsProfiles(data_array, labels_names, items_names): items_profiles = {} for i in range(len(items_names)): items_profiles[items_names[i]] = {} for j in range(len(labels_names)): items_profiles[items_names[i]][labels_names[j]] = data_array[i][j] return items_profiles # 建立使用者畫像 # 引數說明: # data_array: 所有使用者對於其所看過的節目的評分矩陣 data_array = [[2, 0, 0, 1.1, ...], [0, 0, 1.1, ...], ...] # users_profiles = {user1:{'label1':1.1, 'label2': 0.5, 'label3': 0.0, ...}, user2:{...}...} def createUsersProfiles(data_array, users_names, items_names, labels_names, items_profiles): users_profiles = {} # 計算每個使用者對所看過的所有節目的平均隱性評分 # users_average_scores_list = [1.2, 2.2, 4.3,...] users_average_scores_list = [] # 統計每個使用者所看過的節目(不加入隱性評分資訊) # items_users_saw = {user1:[item1, item3, item5], user2:[...],...} items_users_saw = {} # 統計每個使用者所看過的節目及評分 # items_users_saw_scores = {user1:[[item1, 1.1], [item2, 4.1]], user2:...} items_users_saw_scores = {} for i in range(len(users_names)): items_users_saw_scores[users_names[i]] = [] items_users_saw[users_names[i]] = [] count = 0 sum = 0.0 for j in range(len(items_names)): # 使用者對該節目隱性評分為正,表示真正看過該節目 if data_array[i][j] > 0: items_users_saw[users_names[i]].append(items_names[j]) items_users_saw_scores[users_names[i]].append([items_names[j], data_array[i][j]]) count += 1 sum += data_array[i][j] if count == 0: users_average_scores_list.append(0) else: users_average_scores_list.append(sum / count) for i in range(len(users_names)): users_profiles[users_names[i]] = {} for j in range(len(labels_names)): count = 0 score = 0.0 for item in items_users_saw_scores[users_names[i]]: # 引數: # 使用者user1對於型別label1的隱性評分: user1_score_to_label1 # 使用者user1對於其看過的含有型別label1的節目item i 的評分: score_to_item i # 使用者user1對其所看過的所有節目的平均評分: user1_average_score # 使用者user1看過的節目總數: items_count # 公式: user1_score_to_label1 = Sigma(score_to_item i - user1_average_score)/items_count # 該節目含有特定標籤labels_names[j] if items_profiles[item[0]][labels_names[j]] > 0: score += (item[1] - users_average_scores_list[i]) count += 1 # 如果求出的值太小,直接置0 if abs(score) < 1e-6: score = 0.0 if count == 0: result = 0.0 else: result = score / count users_profiles[users_names[i]][labels_names[j]] = result return (users_profiles, items_users_saw) # 建立節目畫像 # 引數說明: # items_profiles = {item1:{'label1':1, 'label2': 0, 'label3': 0, ...}, item2:{...}...} def createItemsProfiles(data_array, labels_names, items_names): items_profiles = {} for i in range(len(items_names)): items_profiles[items_names[i]] = {} for j in range(len(labels_names)): items_profiles[items_names[i]][labels_names[j]] = data_array[i][j] return items_profiles # 計算使用者畫像向量與節目畫像向量的距離(相似度) # 向量相似度計算公式: # cos(user, item) = sigma_ui/sqrt(sigma_u * sigma_i) # 引數說明: # user_profile: 某一使用者user的畫像 user = {'label1':1.1, 'label2': 0.5, 'label3': 0.0, ...} # item: 某一節目item的畫像 item = {'label1':1, 'label2': 0, 'label3': 0, ...} # labels_names: 所有型別名 def calCosDistance(user, item, labels_names): sigma_ui = 0.0 sigma_u = 0.0 sigma_i = 0.0 for label in labels_names: sigma_ui += user[label] * item[label] sigma_u += (user[label] * user[label]) sigma_i += (item[label] * item[label]) if sigma_u == 0.0 or sigma_i == 0.0: # 若分母為0,相似度為0 return 0 return sigma_ui/math.sqrt(sigma_u * sigma_i) # 基於內容的推薦演算法: # 藉助特定某個使用者user的畫像user_profile和備選推薦節目集的畫像items_profiles,通過計算向量之間的相似度得出推薦節目集 # 引數說明: # user_profile: 某一使用者user的畫像 user_profile = {'label1':1.1, 'label2': 0.5, 'label3': 0.0, ...} # items_profiles: 備選推薦節目集的節目畫像: items_profiles = {item1:{'label1':1, 'label2': 0, 'label3': 0}, item2:{...}...} # items_names: 備選推薦節目集中的所有節目名 # labels_names: 所有型別名 # items_user_saw: 使用者user看過的節目 def contentBased(user_profile, items_profiles, items_names, labels_names, items_user_saw): # 對於使用者user的推薦節目集為 recommend_items = [[節目名, 該節目畫像與該使用者畫像的相似度], ...] recommend_items = [] for i in range(len(items_names)): # 從備選推薦節目集中的選擇使用者user沒有看過的節目 if items_names[i] not in items_user_saw: recommend_items.append([items_names[i], calCosDistance(user_profile, items_profiles[items_names[i]], labels_names)]) # 將推薦節目集按相似度降序排列 recommend_items.sort(key=lambda item: item[1], reverse=True) return recommend_items # 輸出推薦給該使用者的節目列表 # max_num:最多輸出的推薦節目數 def printRecommendedItems(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 = ['3','13','23'] #按指定順序排列所有的標籤 all_labels = ['劇情', '西部', '家庭', '驚悚', '動畫', '愛情', '情色', '運動', '音樂', '災難', '懸疑', '兒童', '短片', '歷史', '動作', '科幻', '傳記', '同性', '冒險', '歌舞', '脫口秀', '真人秀', '新聞', '恐怖', '奇幻', '犯罪', '喜劇', '紀錄片', '戰爭', '古裝', '武俠', '綜藝' ,'電視劇', '邵氏','電影'] labels_num = len(all_labels) # 讀取使用者--節目評分矩陣 df1 = pd.read_csv('./wordsbag/dataprocess/data/week/mydata/temp_user_scores_mat.csv',sep=',',encoding='gbk',header='infer',error_bad_lines=False) (m1 , n1) = df1.shape # 所有使用者對其看過的節目的評分矩陣 data_array1 = np.array(df1.iloc[:m1+1 , 1:]) # 按照"所有使用者對其看過的節目的評分矩陣"的列序排列的所有使用者觀看過的節目名稱 items_users_saw_names1 = df1.columns[1:].tolist() # 讀取使用者觀看過的節目及其所屬型別的01矩陣 df2 = pd.read_csv('./wordsbag/dataprocess/data/week/mydata/temp_users_movies_01mat.csv',sep=',',encoding='gbk',header='infer',error_bad_lines=False) (m2 , n2) = df2.shape data_array2 = np.array(df2.iloc[:m2 + 1, 1:]) # print(data_array2) # 按照"所有使用者看過的節目及所屬型別的01矩陣"的列序排列的所有使用者觀看過的節目名稱 #items_users_saw_names2 = np.array(df2.iloc[:m2 + 1, 0]).tolist() #此句語句得不到節目名稱 items_users_saw_names2 = np.array(df2.iloc[:m2 + 1, 0]).tolist() # 為使用者看過的節目建立節目畫像 items_users_saw_profiles = createItemsProfiles(data_array2, all_labels, items_users_saw_names2) # 建立使用者畫像users_profiles和使用者看過的節目集items_users_saw (users_profiles, items_users_saw) = createUsersProfiles(data_array1, all_users_names, items_users_saw_names1, all_labels, items_users_saw_profiles) # 讀取備選節目及其所屬型別的01矩陣 df3 = pd.read_csv('./wordsbag/dataprocess/data/week/mydata/temp_movies_01mat.csv',sep=',',encoding='gbk',header='infer',error_bad_lines=False) (m3 , n3) = df3.shape data_array3 = np.array(df3.iloc[:m3+1, 1:]) # 按照"備選推薦節目集及所屬型別01矩陣"的列序排列的所有使用者觀看過的節目名稱 items_to_be_recommended_names = np.array(df3.iloc[:m3 + 1, 0]).tolist() # 為備選推薦節目集建立節目畫像 items_to_be_recommended_profiles = createItemsProfiles(data_array3, all_labels, items_to_be_recommended_names) #開始推薦 for user in all_users_names: print("給使用者id為 %s 的推薦節目如下:" % user) recommend_items = contentBased(users_profiles[user], items_to_be_recommended_profiles, items_to_be_recommended_names, all_labels, items_users_saw[user]) printRecommendedItems(recommend_items, 5) print('該使用者推薦任務完成。') print( )
執行結果如下:
給使用者id為 3 的推薦節目如下: 節目名:父母愛情, 推薦指數:0.215453 節目名:奔跑吧, 推薦指數:0.171533 節目名:一站到底, 推薦指數:0.171533 節目名:平民英雄, 推薦指數:0.171533 節目名:嚮往的生活, 推薦指數:0.171533 該使用者推薦任務完成。 給使用者id為 13 的推薦節目如下: 節目名:奔跑吧兄弟, 推薦指數:0.630852 節目名:逃學英雄傳, 推薦指數:0.630852 節目名:非誠勿擾, 推薦指數:0.565759 節目名:生財有道, 推薦指數:0.472502 節目名:家庭幽默錄影, 推薦指數:0.446079 該使用者推薦任務完成。 給使用者id為 23 的推薦節目如下: 節目名:檔案, 推薦指數:0.327783 節目名:歡樂頌, 推薦指數:0.293158 節目名:溫暖的弦, 推薦指數:0.293158 節目名:繁星四月, 推薦指數:0.293158 節目名:人間至味是清歡, 推薦指數:0.293158 該使用者推薦任務完成。
該例項的實現要在前幾天文章的前提下進行,原始資料檔案的格式很重要。