1. 程式人生 > >超級詳細的協同過濾推薦系統+完整Python實現及結果

超級詳細的協同過濾推薦系統+完整Python實現及結果

協同過濾推薦系統在我們的日常生活之中無處不在,例如,在電子商城購物,系統會根據使用者的記錄或者其他的

資訊來推薦相應的產品給客戶,是一種智慧的生活方式。之所以交協同過濾,是因為在實現過濾推薦的時候是根據

其他人的行為來做預測的,基於相似使用者的喜好來實現使用者的喜好預測。

簡要介紹:         

通過找到興趣相投,或者有共同經驗的群體,來向用戶推薦感興趣的資訊。

舉例,如何協同過濾,來對使用者A進行電影推薦?

答:簡要步驟如下

找到使用者A(user_id_1)的興趣愛好

找到與使用者A(user_id_1)具有相同電影興趣愛好的使用者群體集合Set<user_id>

找到該群體喜歡的電影集合Set<movie_id>

將這些電影Set<Movie_id>推薦給使用者A(user_id_1)

具體實施步驟如何?

答:簡要步驟如下

(1)畫一個大表格,橫座標是所有的movie_id,縱座標所有的user_id,交叉處代表這個使用者喜愛這部電影

Move_id_1

Move_id_2

Move_id_3

Move_id_4

Move_id_5

……

Move_id_110w

User_id_1

1

1

1

User_id_2

1

1

1

1

User_id_3

1

1

1

1

………….

………….

User_id_10w

1

1

1

如上表:

橫座標,假設有10w部電影,所以橫座標有10w個movie_id,資料來源自資料庫

縱座標,假設有100w個使用者,所以縱座標有100w個user_id,資料也來自資料庫

交叉處,“1”代表使用者喜愛這部電影,資料來自日誌

畫外音:什麼是“喜歡”,需要人為定義,例如瀏覽過,查詢過,點贊過,反正日誌裡有這些資料

(2)找到使用者A(user_id_1)的興趣愛好

如上表,可以看到,使用者A喜歡電影{m1, m2, m3}

(3)找到與使用者A(user_id_1)具有相同電影興趣愛好的使用者群體集合Set<user_id>

如上表,可以看到,喜歡{m1, m2, m3}的使用者,除了u1,還有{u2, u3}

(4)找到該群體喜歡的電影集合Set<movie_id>

如上表,具備相同喜好的使用者群裡{u2, u3},還喜好的電影集合是{m4, m5}

畫外音:“協同”就體現在這裡。

(5)未來使用者A(use_id_1)來訪問網站時,要推薦電影{m4, m5}給ta。

具體實現步驟:

第一步:計算兩者之間的相似度

                       通常會先把二維表格繪製在一個圖中總,每個使用者資料表示一個點。

                       度量相似度計算的方法:a.曼哈頓距離計算(計算迅速,節省時間)

                                                               b.歐氏距離計算(計算兩個點之間的直線距離)

資料預處理:

              或者

解壓讀取movies.csv和ratings.csv檔案

兩個檔案的資料格式如下:

通過如下程式提取資料:

#!/usr/bin/env python
# encoding: utf-8
"""
@Company:華中科技大學電氣學院聚變與等離子研究所
@version: V1.0
@author: YEXIN
@contact: [email protected] or [email protected] 2018--2020
@software: PyCharm
@file: recommend.py
@time: 2018/8/19 17:32
@Desc:讀取使用者的電影資料和評分資料
"""
import  pandas as pd
movies = pd.read_csv("E:\PycharmWorks\ML\CollaborativeFiltering\ml-latest\movies.csv")
ratings = pd.read_csv("E:\PycharmWorks\ML\CollaborativeFiltering\ml-latest\\ratings.csv")##這裡注意如果路徑的中檔名開頭是r,要轉義。
data = pd.merge(movies,ratings,on = 'movieId')#通過兩資料框之間的movieId連線
data[['userId','rating','movieId','title']].sort_values('userId').to_csv('E:\PycharmWorks\ML\CollaborativeFiltering\ml-latest\data.csv',index=False)

結果:

採用python字典來表示每位使用者評論的電影和評分
#!/usr/bin/env python
# encoding: utf-8
"""
@Company:華中科技大學電氣學院聚變與等離子研究所
@version: V1.0
@author: YEXIN
@contact: [email protected] or [email protected] 2018--2020
@software: PyCharm
@file: movie_rating_user.py
@time: 2018/8/19 17:50
@Desc:採用python字典來表示每位使用者評論的電影和評分
"""
file = open("E:\PycharmWorks\ML\CollaborativeFiltering\ml-latest\data.csv",'r', encoding='UTF-8')#記得讀取檔案時加‘r’, encoding='UTF-8'
##讀取data.csv中每行中除了名字的資料
data = {}##存放每位使用者評論的電影和評分
for line in file.readlines()[1:100]:
    #注意這裡不是readline()
    line = line.strip().split(',')
    #如果字典中沒有某位使用者,則使用使用者ID來建立這位使用者
    if not line[0] in data.keys():
        data[line[0]] = {line[3]:line[1]}
    #否則直接新增以該使用者ID為key字典中
    else:
        data[line[0]][line[3]] = line[1]

print(data)

結果(部分):

計算任何兩位使用者之間的相似度,由於每位使用者評論的電影不完全一樣,所以獸先要找到兩位使用者共同評論過的電影

然後計算兩者之間的歐式距離,最後算出兩者之間的相似度。

#!/usr/bin/env python
# encoding: utf-8
"""
@Company:華中科技大學電氣學院聚變與等離子研究所
@version: V1.0
@author: YEXIN
@contact: [email protected] or [email protected] 2018--2020
@software: PyCharm
@file: movie_rating_user.py
@time: 2018/8/19 17:50
@Desc:採用python字典來表示每位使用者評論的電影和評分
"""
file = open("E:\PycharmWorks\ML\CollaborativeFiltering\ml-latest\data.csv",'r', encoding='UTF-8')#記得讀取檔案時加‘r’, encoding='UTF-8'
##讀取data.csv中每行中除了名字的資料
data = {}##存放每位使用者評論的電影和評分
for line in file.readlines()[1:100]:
    #注意這裡不是readline()
    line = line.strip().split(',')
    #如果字典中沒有某位使用者,則使用使用者ID來建立這位使用者
    if not line[0] in data.keys():
        data[line[0]] = {line[3]:line[1]}
    #否則直接新增以該使用者ID為key字典中
    else:
        data[line[0]][line[3]] = line[1]

#print(data)


"""計算任何兩位使用者之間的相似度,由於每位使用者評論的電影不完全一樣,所以獸先要找到兩位使用者共同評論過的電影
       然後計算兩者之間的歐式距離,最後算出兩者之間的相似度
"""
from math import *
def Euclidean(user1,user2):
    #取出兩位使用者評論過的電影和評分
    user1_data=data[user1]
    user2_data=data[user2]
    distance = 0
    #找到兩位使用者都評論過的電影,並計算歐式距離
    for key in user1_data.keys():
        if key in user2_data.keys():
            #注意,distance越大表示兩者越相似
            distance += pow(float(user1_data[key])-float(user2_data[key]),2)

    return 1/(1+sqrt(distance))#這裡返回值越小,相似度越大

#計算某個使用者與其他使用者的相似度
def top10_simliar(userID):
    res = []
    for userid in data.keys():
        #排除與自己計算相似度
        if not userid == userID:
            simliar = Euclidean(userID,userid)
            res.append((userid,simliar))
    res.sort(key=lambda val:val[1])
    return res[:4]

RES = top10_simliar('1')
print(RES)

使用者之間相似度結果:0表示兩位的影評幾乎一樣,1表示沒有共同的影評

根據相似度來推薦使用者:

########################################################################
#根據使用者推薦電影給其他人
def recommend(user):
    #相似度最高的使用者
    top_sim_user = top10_simliar(user)[0][0]
    #相似度最高的使用者的觀影記錄
    items = data[top_sim_user]
    recommendations = []
    #篩選出該使用者未觀看的電影並新增到列表中
    for item in items.keys():
        if item not in data[user].keys():
            recommendations.append((item,items[item]))
    recommendations.sort(key=lambda val:val[1],reverse=True)#按照評分排序
    #返回評分最高的10部電影
    return recommendations[:10]

Recommendations = recommend('1')
print(Recommendations)

推薦結果:

==================================================================================

但有時我們會碰到因為兩個使用者之間資料由於資料膨脹,一方資料大,一方資料小,但是兩者稱明顯的線性關係

我們引入Pearson相關係數來衡量兩個變數之間的線性相關性。

Pearson:-1~1   -1:完全負相關  1:完全正相關  0:不相關              

相關係數 0.8-1.0 極強相關

0.6-0.8 強相關

0.4-0.6 中等程度相關

0.2-0.4 弱相關

0.0-0.2 極弱相關或無相關

公式:

python程式碼:

#########################################################################
##計算兩使用者之間的Pearson相關係數
def pearson_sim(user1,user2):
    # 取出兩位使用者評論過的電影和評分
    user1_data = data[user1]
    user2_data = data[user2]
    distance = 0
    common = {}

    # 找到兩位使用者都評論過的電影
    for key in user1_data.keys():
        if key in user2_data.keys():
            common[key] = 1
    if len(common) == 0:
        return 0#如果沒有共同評論過的電影,則返回0
    n = len(common)#共同電影數目
    print(n,common)

    ##計算評分和
    sum1 = sum([float(user1_data[movie]) for movie in common])
    sum2 = sum([float(user2_data[movie]) for movie in common])

    ##計算評分平方和
    sum1Sq = sum([pow(float(user1_data[movie]),2) for movie in common])
    sum2Sq = sum([pow(float(user2_data[movie]),2) for movie in common])

    ##計算乘積和
    PSum = sum([float(user1_data[it])*float(user2_data[it]) for it in common])

    ##計算相關係數
    num = PSum - (sum1*sum2/n)
    den = sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n))
    if den == 0:
        return 0
    r = num/den
    return r

R = pearson_sim('1','3')
print(R)

pearson係數結果:

注意:通過Pearson係數得到使用者的相似度和通過歐式距離得到結果可能不一樣