1. 程式人生 > >基於內容的推薦演算法的實現程式碼例項

基於內容的推薦演算法的實現程式碼例項

本次例項需要三個資料檔案

分別為節目及其所屬標籤型別的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
該使用者推薦任務完成。

該例項的實現要在前幾天文章的前提下進行,原始資料檔案的格式很重要。

轉載:https://blog.csdn.net/WuchangI/article/details/80160566