1. 程式人生 > >(三)協同過濾演算法之基於物品的推薦演算法python實現

(三)協同過濾演算法之基於物品的推薦演算法python實現

一、背景介紹

網際網路的迅猛發展將人類帶入了資訊社會和網路經濟時代,資訊化影響到了生活的方方面面。但是隨著網際網路產業的擴大,為使用者提供更多選的同時也帶來了篩選與推薦的難題。於是便提出了推薦演算法幫助使用者快速找到自己喜愛的東西。例如京東、淘寶、美團等,在使用者購買物品後,均會給使用者推薦他們可能喜歡的物品,不僅免去了使用者不斷查詢類似物品的煩惱,而且也使得使用者可以貨比多家,最終找到自己物美價廉的商品,而相關的網站平臺也可以提升自己的銷量。電影推薦也是比較常見的,例如使用者觀看了阿甘正傳,可能推薦給使用者肖申克的救贖當幸福來敲門等,推薦相關的應用數不勝數,但其核心就是相關的推薦演算法的組合。
這裡寫圖片描述

二、推薦演算法相關介紹

目前有關個性化推薦演算法主要分為三大類:1.基於協同過濾的推薦;2.基於內容過濾的推薦3.社會化推薦

本文主要討論基於協同過濾的推薦,而該演算法也可以劃分為兩類

1.基於使用者的協同過濾演算法(UserCF)

該演算法利用使用者之間的相似性來推薦使用者感興趣的資訊,個人通過合作的機制給予資訊相當程度的迴應(如評分)並記錄下來以達到過濾的目的進而幫助別人篩選資訊,迴應不一定侷限於特別感興趣的,特別不感興趣資訊的紀錄也相當重要。但有很難解決的兩個問題,一個是稀疏性,即在系統使用初期由於系統資源還未獲得足夠多的評價,很難利用這些評價來發現相似的使用者。另一個是可擴充套件性,隨著系統使用者和資源的增多,系統的效能會越來越差。

2.基於物品的協同過濾演算法(ItemCF)

內容過濾根據資訊資源與使用者興趣的相似性來推薦商品,通過計算使用者興趣模型和商品特徵向量之間的向量相似性,主動將相似度高的商品傳送給該模型的客戶。由於每個客戶都獨立操作,擁有獨立的特徵向量,不需要考慮別的使用者的興趣,不存在評價級別多少的問題,能推薦新的專案或者是冷門的專案。這些優點使得基於內容過濾的推薦系統不受冷啟動和稀疏問題的影響

三、基於物品的推薦演算法以及流程

例如前面背景中介紹的,使用者喜歡看阿甘正傳,且給了高評分後,那麼系統將會尋找與阿甘正傳類似的電影推薦給使用者。

演算法流程
1.構建使用者–>物品的倒排;
2.構建物品與物品的同現矩陣;
3.計算物品之間的相似度,即計算相似矩陣;
4.根據使用者的歷史記錄,給使用者推薦物品;

演算法流程1

構建使用者–>物品的倒排
如下表,行表示使用者,列表示物品,1表示使用者喜歡該物品

使用者\物品 a b c d e
A 1 1 1
B 1 1 1
C 1 1
D 1 1 1
E 1 1
例如python構建的資料格式如下
{
'A': {'a': '1', 'b': '1', 'd': '1'}, 
'B': {'c': '1', 'b': '1', 'e': '1'}, 
'C': {'c': '1', 'd': '1'}, 
'D': {'c': '1', 'b': '1', 'd': '1'},
'E': {'a': '1', 'd': '1'}
}

演算法流程2
構建物品與物品的同現矩陣

共現矩陣C表示同時喜歡兩個物品的使用者數,是根據使用者物品倒排表計算出來的。如根據上面的使用者物品倒排表可以計算出如下的共現矩陣C:

物品\物品 a b c d e
a 1 2
b 1 2 2 1
c 2 2 1
d 2 2 2
e 1 1

演算法流程3

計算物品之間的相似度,即計算相似矩陣

其中兩個物品之間的相似度如何計算?
設|N(i)|表示喜歡物品i的使用者數,|N(i)⋂N(j)|表示同時喜歡物品i,j的使用者數,則物品i與物品j的相似度為:
(1)wij=|N(i)N(j)||N(i)|
(1)式有一個問題,當物品j是一個很熱門的商品時,人人都喜歡,那麼wij就會很接近於1,即(1)式會讓很多物品都和熱門商品有一個很大的相似度,所以可以改進一下公式:

(2)wij=|N(i)N(j)||N(i)||N(j)|

演算法流程2中的共現矩陣C其實就是式(2)的分子,矩陣N(用於計算分母)表示喜歡某物品的使用者數(是總的使用者數),則(2)式中的分母便很容易求解出來了。

矩陣N如下所示:

物品 a b c d e
使用者數 2 3 3 4 1

利用式(2)便能計算物品之間的餘弦相似矩陣如下:

物品\物品 a b c d e
a 0.41 0.71
b 0.41 0.67 0.58 0.58
c 0.67 0.58 0.58
d 0.71 0.58 0.58
e 0.58 0.58

演算法流程4

根據使用者的歷史記錄,給使用者推薦物品;

最終推薦的是什麼物品,是由預測興趣度決定的。

物品j預測興趣度=使用者喜歡的物品i的興趣度×物品i和物品j的相似度

例如:A使用者喜歡a,b,d ,興趣度分別為1,1,1

  • 推薦c的預測興趣度=1X0.67+1X0.58=1.25
  • 推薦e的預測興趣度=1X0.58=0.58

四、python實現演算法

1.資料描述

該資料為使用者,興趣度,物品

    #使用者,興趣度,物品
    uid_score_bid = ['A,1,a', 'A,1,b', 'A,1,d', 'B,1,b', 'B,1,c', 'B,1,e', 'C,1,c', 'C,1,d', 'D,1,b', 'D,1,c', 'D,1,d',
                     'E,1,a', 'E,1,d'];

2.python實現物品推薦

#!/usr/bin/python
# -*- coding: UTF-8 -*-
from math import sqrt
import operator

#1.構建使用者-->物品的倒排
def loadData(files):
    data ={};
    for line in files:
        user,score,item=line.split(",");
        data.setdefault(user,{});
        data[user][item]=score;
    print "----1.使用者:物品的倒排----"
    print data
    return data

#2.計算
# 2.1 構造物品-->物品的共現矩陣
# 2.2 計算物品與物品的相似矩陣
def similarity(data):
    # 2.1 構造物品:物品的共現矩陣
    N={};#喜歡物品i的總人數
    C={};#喜歡物品i也喜歡物品j的人數
    for user,item in data.items():
        for i,score in item.items():
            N.setdefault(i,0);
            N[i]+=1;
            C.setdefault(i,{});
            for j,scores in item.items():
                if j not in i:
                    C[i].setdefault(j,0);
                    C[i][j]+=1;

    print "---2.構造的共現矩陣---"
    print ('N:',N);
    print ('C',C);

    #2.2 計算物品與物品的相似矩陣
    W={};
    for i,item in C.items():
        W.setdefault(i,{});
        for j,item2 in item.items():
            W[i].setdefault(j,0);
            W[i][j]=C[i][j]/sqrt(N[i]*N[j]);
    print "---3.構造的相似矩陣---"
    print W
    return W

#3.根據使用者的歷史記錄,給使用者推薦物品
def recommandList(data,W,user,k=3,N=10):
    rank={};
    for i,score in data[user].items():#獲得使用者user歷史記錄,如A使用者的歷史記錄為{'a': '1', 'b': '1', 'd': '1'}
        for j,w in sorted(W[i].items(),key=operator.itemgetter(1),reverse=True)[0:k]:#獲得與物品i相似的k個物品
            if j not in data[user].keys():#該相似的物品不在使用者user的記錄裡
                rank.setdefault(j,0);
                rank[j]+=float(score) * w;

    print "---4.推薦----"
    print sorted(rank.items(),key=operator.itemgetter(1),reverse=True)[0:N];
    return sorted(rank.items(),key=operator.itemgetter(1),reverse=True)[0:N];

if __name__=='__main__':
    #使用者,興趣度,物品
    uid_score_bid = ['A,1,a', 'A,1,b', 'A,1,d', 'B,1,b', 'B,1,c', 'B,1,e', 'C,1,c', 'C,1,d', 'D,1,b', 'D,1,c', 'D,1,d',
                     'E,1,a', 'E,1,d'];
    data=loadData(uid_score_bid);#獲得資料
    W=similarity(data);#計算物品相似矩陣
    recommandList(data,W,'A',3,10);#推薦

實驗結果如下:

----1.使用者:物品的倒排----
{'A': {'a': '1', 'b': '1', 'd': '1'}, 'C': {'c': '1', 'd': '1'}, 'B': {'c': '1', 'b': '1', 'e': '1'}, 'E': {'a': '1', 'd': '1'}, 'D': {'c': '1', 'b': '1', 'd': '1'}}

---2.構造的共現矩陣---
('N:', {'a': 2, 'c': 3, 'b': 3, 'e': 1, 'd': 4})
('C', {'a': {'b': 1, 'd': 2}, 'c': {'b': 2, 'e': 1, 'd': 2}, 'b': {'a': 1, 'c': 2, 'e': 1, 'd': 2}, 'e': {'c': 1, 'b': 1}, 'd': {'a': 2, 'c': 2, 'b': 2}})

---3.構造的相似矩陣---
{'a': {'b': 0.4082482904638631, 'd': 0.7071067811865475}, 'c': {'b': 0.6666666666666666, 'e': 0.5773502691896258, 'd': 0.5773502691896258}, 'b': {'a': 0.4082482904638631, 'c': 0.6666666666666666, 'e': 0.5773502691896258, 'd': 0.5773502691896258}, 'e': {'c': 0.5773502691896258, 'b': 0.5773502691896258}, 'd': {'a': 0.7071067811865475, 'c': 0.5773502691896258, 'b': 0.5773502691896258}}

---4.推薦----
[('c', 1.2440169358562925), ('e', 0.5773502691896258)]

五、電影推薦應用小案例

1.電影資料描述

    電影資料很多,在此示範下基於物品的電影推薦,資料為基於使用者--->電影的倒排,資料如下
    data = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
                          'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
                          'The Night Listener': 3.0},

            'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
                             'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
                             'You, Me and Dupree': 3.5},

            'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
                                 'Superman Returns': 3.5, 'The Night Listener': 4.0},

            'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
                             'The Night Listener': 4.5, 'Superman Returns': 4.0,
                             'You, Me and Dupree': 2.5},

            'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
                             'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
                             'You, Me and Dupree': 2.0},

            'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
                              'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},

            'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
            }

2.推薦
推薦過程和上面的程式碼過程一樣,僅不用構造倒排資料

#!/usr/bin/python
# -*- coding: UTF-8 -*-
from math import sqrt
import operator

#1.構建使用者-->物品的倒排(此推薦無需使用)
def loadData(files):
    data ={};
    for line in files:
        user,score,item=line.split(",");
        data.setdefault(user,{});
        data[user][item]=score;
    print "----1.使用者:物品的倒排----"
    print data
    return data

#2.計算
# 2.1 構造物品-->物品的共現矩陣
# 2.2 計算物品與物品的相似矩陣
def similarity(data):
    # 2.1 構造物品:物品的共現矩陣
    N={};#喜歡物品i的總人數
    C={};#喜歡物品i也喜歡物品j的人數
    for user,item in data.items():
        for i,score in item.items():
            N.setdefault(i,0);
            N[i]+=1;
            C.setdefault(i,{});
            for j,scores in item.items():
                if j not in i:
                    C[i].setdefault(j,0);
                    C[i][j]+=1;

    print "---2.構造的共現矩陣---"
    print ('N:',N);
    print ('C',C);

    #2.2 計算物品與物品的相似矩陣
    W={};
    for i,item in C.items():
        W.setdefault(i,{});
        for j,item2 in item.items():
            W[i].setdefault(j,0);
            W[i][j]=C[i][j]/sqrt(N[i]*N[j]);
    print "---3.計算的相似矩陣---"
    print W
    return W

#3.根據使用者的歷史記錄,給使用者推薦物品
def recommandList(data,W,user,k=3,N=10):
    rank={};
    for i,score in data[user].items():#獲得使用者user歷史記錄,如A使用者的歷史記錄為{'a': '1', 'b': '1', 'd': '1'}
        for j,w in sorted(W[i].items(),key=operator.itemgetter(1),reverse=True)[0:k]:#獲得與物品i相似的k個物品
            if j not in data[user].keys():#該相似的物品不在使用者user的記錄裡
                rank.setdefault(j,0);
                rank[j]+=float(score) * w;

    print "---3.推薦----"
    print sorted(rank.items(),key=operator.itemgetter(1),reverse=True)[0:N];
    return sorted(rank.items(),key=operator.itemgetter(1),reverse=True)[0:N];

if __name__=='__main__':
    print "---1.構造資料---"
    data = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
                          'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
                          'The Night Listener': 3.0},

            'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
                             'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
                             'You, Me and Dupree': 3.5},

            'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
                                 'Superman Returns': 3.5, 'The Night Listener': 4.0},

            'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
                             'The Night Listener': 4.5, 'Superman Returns': 4.0,
                             'You, Me and Dupree': 2.5},

            'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
                             'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
                             'You, Me and Dupree': 2.0},

            'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
                              'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},

            'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
            }
    W=similarity(data);#計算物品相似矩陣
    recommandList(data,W,'Toby',10,10);#推薦

推薦結果:

---1.構造資料---

---2.構造的共現矩陣---
('N:', {'Lady in the Water': 5, 'Snakes on a Plane': 7, 'Just My Luck': 4, 'Superman Returns': 7, 'The Night Listener': 6, 'You, Me and Dupree': 6})
('C', {'Lady in the Water': {'Snakes on a Plane': 5, 'Just My Luck': 3, 'The Night Listener': 5, 'Superman Returns': 5, 'You, Me and Dupree': 4}, 'Snakes on a Plane': {'Lady in the Water': 5, 'Just My Luck': 4, 'The Night Listener': 6, 'Superman Returns': 7, 'You, Me and Dupree': 6}, 'Just My Luck': {'Lady in the Water': 3, 'Snakes on a Plane': 4, 'The Night Listener': 4, 'Superman Returns': 4, 'You, Me and Dupree': 4}, 'Superman Returns': {'Lady in the Water': 5, 'Snakes on a Plane': 7, 'The Night Listener': 6, 'Just My Luck': 4, 'You, Me and Dupree': 6}, 'The Night Listener': {'Lady in the Water': 5, 'Snakes on a Plane': 6, 'Just My Luck': 4, 'Superman Returns': 6, 'You, Me and Dupree': 5}, 'You, Me and Dupree': {'Lady in the Water': 4, 'Snakes on a Plane': 6, 'Just My Luck': 4, 'Superman Returns': 6, 'The Night Listener': 5}})

---3.計算的相似矩陣---
{'Lady in the Water': {'Snakes on a Plane': 0.8451542547285166, 'Just My Luck': 0.6708203932499369, 'You, Me and Dupree': 0.7302967433402214, 'Superman Returns': 0.8451542547285166, 'The Night Listener': 0.9128709291752769}, 'Snakes on a Plane': {'Lady in the Water': 0.8451542547285166, 'Just My Luck': 0.7559289460184544, 'You, Me and Dupree': 0.9258200997725514, 'Superman Returns': 1.0, 'The Night Listener': 0.9258200997725514}, 'Just My Luck': {'Lady in the Water': 0.6708203932499369, 'Snakes on a Plane': 0.7559289460184544, 'You, Me and Dupree': 0.8164965809277261, 'Superman Returns': 0.7559289460184544, 'The Night Listener': 0.8164965809277261}, 'Superman Returns': {'Lady in the Water': 0.8451542547285166, 'Snakes on a Plane': 1.0, 'Just My Luck': 0.7559289460184544, 'You, Me and Dupree': 0.9258200997725514, 'The Night Listener': 0.9258200997725514}, 'You, Me and Dupree': {'Lady in the Water': 0.7302967433402214, 'Snakes on a Plane': 0.9258200997725514, 'Just My Luck': 0.8164965809277261, 'Superman Returns': 0.9258200997725514, 'The Night Listener': 0.8333333333333334}, 'The Night Listener': {'Lady in the Water': 0.9128709291752769, 'Snakes on a Plane': 0.9258200997725514, 'Just My Luck': 0.8164965809277261, 'Superman Returns': 0.9258200997725514, 'You, Me and Dupree': 0.8333333333333334}}

---4.推薦----
[('The Night Listener', 8.70280418140002), ('Lady in the Water', 7.914107908532612), ('Just My Luck', 7.241892622084588)]