機器學習-推薦系統之基於用戶的協同過濾

人以羣分 – 基於用戶的協同過濾(User Collaborative Filtering,簡稱User CF)

生活中可能有這樣的朋友:他喜歡的書、電影,你也喜歡;
他喜歡的衣服款式、美食餐廳你也十分推崇;
……
在這裏插入圖片描述

基本原理:

  • 通過用戶對不同內容(物品)的行爲,來評測用戶之間的相似性,找到“鄰居”基於這種相似性做出推薦:
  • 這種推薦的本質是,給相似的用戶推薦其他用戶喜歡的內容;
  • 這就是我們經常看到的:和你類似的人還喜歡如下內容。
    在這裏插入圖片描述

基本方法:

① 找到和目標用戶興趣相似的用戶集合(關鍵在於計算兩個用戶之間的興趣相似度);
② 找到這個集合中的用戶所喜歡的,並且目標用戶沒有聽說過的物品推薦給目標用戶。

如何找到和你相似的人?

類比於KNN中K個“鄰居”的尋找方法——通過距離衡量相近程度。
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述 閔科夫斯基距離

用戶相似性計算指標:

皮爾遜相關係數

在這裏插入圖片描述

餘弦相關係數

在這裏插入圖片描述

傑卡德相關係數

在這裏插入圖片描述

User CF步驟

在這裏插入圖片描述• 讀入用戶評分
• 計算用戶相似性
• 根據用戶相似性排序選擇前K個鄰居
• 根據K個鄰居的評分項目預測用戶評分
• 選擇預測評分最高的前N個項目作爲推薦列表

代碼實現

import numpy as np
import pandas as pd
#讀取數據文檔
df = pd.read_csv('example.csv')
df.head()

在這裏插入圖片描述

#建立關係矩陣rating
dfpivot= df.pivot_table(index="用戶id",columns="物品id",values="評分",fill_value=0)
dfpivot

在這裏插入圖片描述

#獲取關係矩陣
freq_matrix = dfpivot.values
freq_matrix
array([[1, 0, 2, 0, 0, 1],
       [0, 0, 4, 2, 0, 0],
       [3, 5, 0, 4, 4, 3],
       [0, 4, 1, 0, 3, 0],
       [0, 0, 2, 5, 4, 3],
       [5, 0, 0, 0, 2, 0],
       [0, 4, 3, 0, 0, 0],
       [0, 0, 0, 4, 0, 2],
       [5, 0, 4, 0, 0, 0],
       [0, 2, 3, 0, 0, 0],
       [4, 1, 5, 2, 2, 4],
       [0, 3, 0, 0, 5, 0]], dtype=int64)

各類相似度計算函數的構建

歐式距離

在這裏插入圖片描述

def o_dist(u1,u2):  
    re = np.sqrt(sum((u1-u2)**2))
    return re
u1 = freq_matrix[2,:]
u2 = freq_matrix[3,:]
o_dist(u1,u2)
6.082762530298219

曼哈頓距離

在這裏插入圖片描述

def manh_dist(u1,u2):
    re = sum(abs(u1-u2))
    return re
u1 = freq_matrix[2,:]
u2 = freq_matrix[3,:]
manh_dist(u1,u2)
13

餘弦相似度

在這裏插入圖片描述

def cos_dist(u1,u2):
    fenzi = sum(u1*u2)
    len_1 = np.sqrt(sum(u1**2))
    len_2 = np.sqrt(sum(u2**2))
    return fenzi/(len_1*len_2)
u1 = freq_matrix[2,:]
u2 = freq_matrix[3,:]
cos_dist(u1,u2)
0.7246573018525412

皮爾遜相關係數

在這裏插入圖片描述

def pear_dist(u1,u2):
    fenzi = sum((u1-u1.mean())*(u2-u2.mean()))
    fenmu = np.sqrt(sum((u1-u1.mean())**2)*sum((u2-u2.mean())**2))
    return fenzi/fenmu
pear_dist(u1,u2)
0.4420496737025353
#通過調包實現皮爾遜相關係數
from scipy.stats import pearsonr 
u1 = freq_matrix[2,:]
u2 = freq_matrix[3,:]
r,pVal = pearsonr(u1, u2)
r
0.4420496737025353

使用餘弦相似度計算物品相似度矩陣

n_users = freq_matrix.shape[0] #用戶數
sim = np.zeros((n_users,n_users))
for i in range(n_users):
    for j in range(n_users):
        sim[i][j] = cos_dist(freq_matrix[i,:],freq_matrix[j,:])
pd.DataFrame(sim)

在這裏插入圖片描述

#也可以直接調庫實現
from sklearn.metrics.pairwise import cosine_similarity
user_similar=cosine_similarity(freq_matrix)
pd.DataFrame(user_similar)

在這裏插入圖片描述

構建推薦指數函數

計算公式:
rxi=yN(x;i)sxyryiyN(x;i)sxy r_{xi}=\frac{\sum_{y \in {N(x;i)}}s_{xy}⋅r_{yi} }{\sum_{y \in {N(x;i)}}s_{xy}}
𝑟𝑥𝑖:預測用戶𝑥對物品𝑖的評分
𝑟𝑦𝑖:預測用戶𝑦對物品𝑖的評分
𝑠𝑥𝑦:用戶𝑥和用戶𝑦之間的相似度
𝑁(𝑥;𝑖):與用戶𝑥相似的用戶對物品𝑖的評分集合

#構建一個基於用戶的推薦
def Recommendation(uid,iid,similar,k=10):
    score = 0
    weight = 0
    user_id_action = freq_matrix[uid,:]      #用戶user_id 對所有商品的行爲評分  
    item_id_action = freq_matrix[:,iid]      #物品item_id 得到的所有用戶評分  

    user_id_similar = similar[uid,:]      #用戶user_id 對所有用戶的相似度    
    similar_index = np.argsort(user_id_similar)[-(k+1):-1]  #最相似的k個用戶的index(除了自己)
    
    for j in similar_index :
        if item_id_action[j]!=0:
            user_id_j_action = freq_matrix[j,:]
            score += user_id_similar[j]*(item_id_action[j])
            weight += abs(user_id_similar[j])

    if weight==0:  
        return 0
    else:
        return score/weight
Recommendation(4,0,user_similar,k=3)

構建預測函數

#構建預測函數
def predict(similar):
    """預測函數的功能: 傳入相似度矩陣, 通過對每個用戶和每個物品進行計算, 計算出一個推薦矩陣"""
    user_count = freq_matrix.shape[0]#用戶數
    item_count = freq_matrix.shape[1]#商品數
    predic_matrix = np.zeros((user_count,item_count))
    for uid in range(user_count):
        for iid in range(item_count):
            if freq_matrix[uid,iid] == 0:
                predic_matrix[uid,iid] = Recommendation(uid,iid,similar)
    return predic_matrix
user_prediction_matrix = predict(user_similar)
pd.DataFrame(user_prediction_matrix)

在這裏插入圖片描述

構建最終的Topk推薦函數

def get_topk(group,k):
    # 返回排序後的前幾個值
    return group.sort_values("推薦指數",ascending=False)[:k]
def get_recommendation(user_prediction_matrix,k=5):
    # 將用戶預測數據, 構建成一個DataFrame
    recommendation_df = pd.DataFrame(user_prediction_matrix,columns=dfpivot.columns,index=dfpivot.index)
    # 將數據進行轉換
    recommendation_df = recommendation_df.stack().reset_index()
    # 對列名進行修改
    recommendation_df.rename(columns={0:"推薦指數"},inplace=True)
    # 根據用戶ID列進行分組
    grouped = recommendation_df.groupby("用戶id")
    # 得到分組後的前幾個數據
    topk = grouped.apply(get_topk,k=k)
    
    # 刪除掉用戶ID列
    topk = topk.drop(["用戶id"],axis=1)
    # 刪除掉多餘的索引
    topk.index = topk.index.droplevel(1)
    # 索引重排
    topk.reset_index(inplace=True)
    return topk
top3 = get_recommendation(user_prediction_matrix,k=3)
top3

在這裏插入圖片描述
…… ……

模型改進

#構建一個基於用戶的推薦
def Recommendation_mean(uid,iid,similar,k=10):
    """減去平均數的計算方法"""
    score = 0
    weight = 0
    user_id_action = freq_matrix[uid,:]      #用戶user_id 對所有商品的行爲評分  
    item_id_action = freq_matrix[:,iid]      #物品item_id 得到的所有用戶評分  

    user_id_similar = similar[uid,:]      #用戶user_id 對所有用戶的相似度    
    similar_index = np.argsort(user_id_similar)[-(k+1):-1]  #最相似的k個用戶的index(除了自己)
    user_id_i_mean = np.sum(user_id_action)/user_id_action[user_id_action!=0].size#
    for j in similar_index :
        if item_id_action[j]!=0:
            user_id_j_action = freq_matrix[j,:]
            user_id_j_mean = np.sum(user_id_j_action)/user_id_j_action[user_id_j_action!=0].size
            score += user_id_similar[j]*(item_id_action[j]-user_id_j_mean)
            weight += abs(user_id_similar[j])

    if weight==0:  
        return 0
    else:
        return user_id_i_mean + score/weight
Recommendation_mean(4,0,user_similar,k=3)
3.5757660020086943
#構建預測函數
def predict_mean(similar):
    """預測函數的功能: 傳入相似度矩陣, 通過對每個用戶和每個物品進行計算, 計算出一個推薦矩陣"""
    user_count = freq_matrix.shape[0]#用戶數
    item_count = freq_matrix.shape[1]#商品數
    predic_matrix = np.zeros((user_count,item_count))
    for uid in range(user_count):
        for iid in range(item_count):
            if freq_matrix[uid,iid] == 0:
                predic_matrix[uid,iid] = Recommendation_mean(uid,iid,similar)
    return predic_matrix
user_prediction_matrix_mean = predict_mean(user_similar)
top3_mean = get_recommendation(user_prediction_matrix_mean,k=3)
top3_mean

在這裏插入圖片描述
…… ……

User CF侷限性

• 每次計算用戶之間相似度時,需要遍歷所有用戶及其評分;
• 在網站用戶增長到一定程度後,計算用戶之間的相似度過程將會變得越發複雜和困難;
• 此外,基於用戶的協同過濾方法數學性不是很好(即不是很容易從數學原理的角度去解釋);
• 用戶口味變化極快,不是靜態的,所以興趣遷移問題很難反應出來;
• 數據稀疏,用戶和用戶之間有共同消費行爲實際上比較少,而且一般是熱門物品,對發現用戶興趣幫助不大。
因此,全球著名的電子商務公司亞馬遜的研發團隊,提出了基於物品的協同過濾算法(Item-to-Item Collaborative Filtering,簡稱ItemCF),用來給用戶推薦那些和他們之前喜歡的物品相似的物品。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章