1. 程式人生 > >簡單的協同過濾演算法程式碼 推薦系統

簡單的協同過濾演算法程式碼 推薦系統

推薦系統  簡單的協同過濾程式碼

參考:https://blog.csdn.net/u012332571/article/details/52206055部落格

問題:7個人對不同電影的評分,根據評分計算使用者的相似度

資料為:

critics={
    '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}
    }

一. 基於使用者的協同過濾

通俗地說,就是找到與目標使用者相似的使用者,推薦給目標使用者相似使用者喜歡的物品。

1.計算使用者相似度

1.1歐幾里得距離

d=(p1p2)2

(注:p1代表使用者1對電影v的評分,p2代表使用者2對電影v的評分,其中v 是使用者1和使用者2共同評分的電影)

在實際應用中,希望相似度越大,返回的值越大,並且值控制在0到1之間,因此我們取函式值加1的倒數(加1是為了防止除0的情況)

#1.歐幾里得距離
def sim_distance(prefs,person1,person2):
    #建立一個空集合用來儲存使用者1和使用者2都有的電影的評分
    si = {}
    for item in prefs[person1]:
        if item in prefs[person2]:
            si[item] = 1
    #如果兩個人沒有共同的評分,則返回0
    if len(si) == 0:
        return 0
    #計算所有距離的和(差值的平方和)
    sum_of_squares = sum([pow(prefs[person1][item]-prefs[person2][item],2)
                          for item in prefs[person1] if item in prefs[person2]])
    return 1 / (1 + sqrt(sum_of_squares))#分子上加1,是為了防止分母為0
輸入:
import recommendations
critics = recommendations.critics
print(recommendations.sim_distance(critics,'Lisa Rose','Gene Seymour'))

可得,兩使用者的相似度為0.29429805508554946

1.2皮爾遜相關係數

採用和參考部落格中不一樣的公式,得到相同的結果。

def sim_pearson2(prefs,p1,p2): #另一種方法也行
    si = {}
    ci = {}
    di = {}
    for item in prefs[p1]:
        ci[item] = 1
    n1 = len(ci)
    for item in prefs[p2]:
        di[item] = 1
    n2 = len(di)
    for item in prefs[p1]:
        if item in prefs[p2]:
            si[item] = 1
    n = len(si)
    if n == 0:
        return 1  # 為什麼不是0?
    # 對所有偏好求和(也是對兩者共同的電影來說)
    u1 = sum([prefs[p1][item] for item in ci]) / n1
    u2 = sum([prefs[p2][item] for item in di]) / n2
    # 乘積之和
    num = sum([(prefs[p1][item] - u1) * (prefs[p2][item] - u2) for item in si])
    # 計算皮爾遜相關係數
    s1 = sum([pow((prefs[p1][item] - u1),2) for item in si])
    s2 = sum([pow((prefs[p2][item] - u2),  2) for item in si])
    den = sqrt(s1) * sqrt(s2)

    if den == 0:
        return 0
    r = num / den
    return r

同理,也可得到兩個使用者的相似度。

2.根據使用者相似度,求與某一使用者相近的其他使用者的前幾名(從字典裡選取品味最近的使用者)

def topMatches(prefs,person,n = 5,similarity = sim_pearson):
    #求引數使用者和其他所有使用者的相似係數
    scores =[(similarity(prefs,person,other),other) for other in prefs if other != person]
    #對列表進行排序,評價值最高者排在最前面
    scores.sort()
    scores.reverse()
    return scores[0:n]
輸入:
print(recommendations.topMatches(critics, 'Toby', n=3))

得到和使用者“Toby”相似的前3位使用者:

[(0.9912407071619299, 'Lisa Rose'), (0.9244734516419049, 'Mick LaSalle'), (0.8934051474415647, 'Claudia Puig')]

3.根據品味相近的使用者給目標使用者推薦沒有看過的電影(利用所有相似使用者的加權平均,為某人提供建議)

def getRecommendations(prefs,person,similarity = sim_pearson):
    totals = {}
    simSums = {}
    for other in prefs:
        if other == person:continue
        sim = similarity(prefs,person,other)
        #忽略相似值為零或者小於零的情況
        if sim <= 0: continue
        for item in prefs[other]:
            #只對自己沒有看過的電影評價
            if item not in prefs[person] or prefs[person][item] == 0:
                #相似度*評價值
                totals.setdefault(item,0)#.setdefault:如果鍵在字典中,返回這個鍵所對應的值。如果鍵不在字典中,向字典中插入這個鍵,返回值為0.
                totals[item] += prefs[other][item]*sim
                #相似度之和
                simSums.setdefault(item,0)
                simSums[item]+= sim
        #建立一個列表,列表裡面是person沒有看過的電影和評分
        rangkings=[(totals / simSums[item],item) for item, totals in totals.items()]
        #排序
        rangkings.sort()
        rangkings.reverse()
        return rangkings
輸入:
print(recommendations.getRecommendations(critics,'Michael Phillips'))

得到對使用者Michael Phillips推薦的電影和評分

[(3.5, 'You, Me and Dupree'), (1.5, 'Just My Luck')]

二、基於物品的協同過濾

1.可以把使用者和電影反過來,和尋找品味相近的使用者一樣,來尋找類似的電影。

def transformPrefs(prefs):
    result={}
    for person in prefs:
        for item in prefs[person]:
            result.setdefault(item,{})
            result[item][person] = prefs[person][item]
    return result

輸入:print(recommendations.transformPrefs(critics)) 檢視轉換後的資料

2.給使用者推薦物品的時候,通過物品相似度,還有相似物品的評分,通過公式計算,就能得出推薦使用者未購買或者評分的物品評分

#基於物品的協同過濾
def  calculateSimilarItems(prefs,n=10):
   #與這些電影最為相近的其他所有電影
   result = {}
   #以物品為中心對偏好矩陣實施倒置處理
   itemPrefs = transformPrefs(prefs)
   c = 0
   for item in itemPrefs:
       scores = topMatches(itemPrefs,item,n=n,similarity=sim_distance)
       result[item] = scores
   return result

def getRecommendedItems(prefs,itemMatch,user):
    userRatings = prefs[user]
    scores ={}
    totalSim={}
    #迴圈遍歷與當前物品相近的物品
    for (item, rating) in userRatings.items():
        for (similarity, item2) in itemMatch[item]:
            # 如果該使用者已經對當前物品做出過評價,就忽略
            if item2 in userRatings: continue
            # 評價值與相似度的加權之和
            scores.setdefault(item2, 0)
            scores[item2] += similarity * rating
            # 全部相似度之和
            totalSim.setdefault(item2, 0)
            totalSim[item2] += similarity
        # 將每個和值除以加權和,求平均值
    rankings = [(score / totalSim[item], item) for item, score in scores.items()]
    # 排序
    rankings.sort()
    rankings.reverse()
    return rankings

輸入:

itemsim = recommendations.calculateSimilarItems(critics)

print(itemsim)

輸出:{'Snakes on a Plane': [(0.3483314773547883, 'Lady in the Water'), (0.32037724101704074, 'The Night Listener'), (0.3090169943749  。。。。。

輸入:

itemsim = recommendations.calculateSimilarItems(critics)

print(recommendations.getRecommendedItems(critics, itemsim, 'Toby'))

輸出:[(3.1667425234070894, 'The Night Listener'), (2.9366294028444355, 'Just My Luck'), (2.8687673926264674, 'Lady in the Water')]

有關運用該程式碼處理MovieLens資料的,下次再寫有關部落格。