1. 程式人生 > >基於使用者的電視節目推薦演算法例項

基於使用者的電視節目推薦演算法例項

# -*- 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

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