推薦系統之矩陣分解(MF)


一、矩陣分解

1.案例

我們都熟知在一些軟件中常常有評分系統,但並不是所有的用戶user人都會對項目item進行評分,因此評分系統所收集到的用戶評分信息必然是不完整的矩陣。那如何跟據這個不完整矩陣中已有的評分來預測未知評分呢。使用矩陣分解的思想很好地解決了這一問題。
假如我們現在有一個用戶-項目的評分矩陣R(n,m)是n行m列的矩陣,n表示user個數,m行表示item的個數

那么,如何根據目前的矩陣R(5,4)如何對未打分的商品進行評分的預測(如何得到分值為0的用戶的打分值)?

——矩陣分解的思想可以解決這個問題,其實這種思想可以看作是有監督的機器學習問題(回歸問題)。

矩陣分解的過程中,,矩陣R可以近似表示為矩陣P與矩陣Q的乘積:

矩陣P(n,k)表示n個user和k個特征之間的關系矩陣,這k個特征是一個中間變量,矩陣Q(k,m)的轉置是矩陣Q(m,k),矩陣Q(m,k)表示m個item和K個特征之間的關系矩陣,這里的k值是自己控制的,可以使用交叉驗證的方法獲得最佳的k值。為了得到近似的R(n,m),必須求出矩陣P和Q,如何求它們呢?

2.推導步驟

1.首先令:

2。對於式子1的左邊項,表示的是r^ 第i行,第j列的元素值,對於如何衡量,我們分解的好壞呢,式子2,給出了衡量標准,也就是損失函數,平方項損失,最后的目標,就是每一個元素(非缺失值)的e(i,j)的總和最小值

3.使用梯度下降法獲得修正的p和q分量:

  • 求解損失函數的負梯度

  • 根據負梯度的方向更新變量:

4.不停迭代直到算法最終收斂(直到sum(e^2) <=閾值,即梯度下降結束條件:f(x)的真實值和預測值小於自己設定的閾值)

5.為了防止過擬合,增加正則化項

3.加入正則項的損失函數求解

1.通常在求解的過程中,為了能夠有較好的泛化能力,會在損失函數中加入正則項,以對參數進行約束,加入正則L2范數的損失函數為:

對正則化不清楚的,公式可化為:

2.使用梯度下降法獲得修正的p和q分量:

  • 求解損失函數的負梯度:

  • 根據負梯度的方向更新變量:

4.預測

預測利用上述的過程,我們可以得到矩陣和,這樣便可以為用戶 i 對商品 j 進行打分:

二、代碼實現

import numpy as np  
import matplotlib.pyplot as plt
 
 
def matrix(R, P, Q, K, alpha, beta):
    result=[]
    steps = 1
    while 1 :
    #使用梯度下降的一步步的更新P,Q矩陣直至得到最終收斂值
        steps = steps + 1    
        eR = np.dot(P,Q)
        e=0
        for i in range(len(R)):
            for j in range(len(R[i])):
                if R[i][j]>0:
                    # .dot(P,Q) 表示矩陣內積,即Pik和Qkj k由1到k的和eij為真實值和預測值的之間的誤差,
                    eij=R[i][j]-np.dot(P[i,:],Q[:,j]) 
                    #求誤差函數值,我們在下面更新p和q矩陣的時候我們使用的是化簡得到的最簡式,較為簡便,
                    #但下面我們仍久求誤差函數值這里e求的是每次迭代的誤差函數值,用於繪制誤差函數變化圖
                    e=e+pow(R[i][j] - np.dot(P[i,:],Q[:,j]),2) 
                    for k in range(K):
                        #在上面的誤差函數中加入正則化項防止過擬合
                        e=e+(beta/2)*(pow(P[i][k],2)+pow(Q[k][j],2))
                        
                    for k in range(K):
                        #在更新p,q時我們使用化簡得到了最簡公式
                        P[i][k]=P[i][k]+alpha*(2*eij*Q[k][j]-beta*P[i][k])
                        Q[k][j]=Q[k][j]+alpha*(2*eij*P[i][k]-beta*Q[k][j])
        print('迭代輪次:', steps, '   e:', e)
        result.append(e)#將每一輪更新的損失函數值添加到數組result末尾
        
        #當損失函數小於一定值時,迭代結束
        if eij<0.00001:
            break
    return P,Q,result
 
 
    
R=[
   [5,3,1,1,4],
   [4,0,0,1,4],
   [1,0,0,5,5],
   [1,3,0,5,0],
   [0,1,5,4,1],
   [1,2,3,5,4]
   ]
 
R=np.array(R)
    
alpha = 0.0001 #學習率
beta = 0.002 
 
N = len(R) #表示行數
M = len(R[0]) #表示列數
K = 3 #3個因子
 
p = np.random.rand(N, K) #隨機生成一個 N行 K列的矩陣
q = np.random.rand(K, M) #隨機生成一個 M行 K列的矩陣
 
P, Q, result=matrix(R, p, q, K,  alpha, beta)
print("矩陣Q為:\n",Q)
print("矩陣P為:\n",P)
print("矩陣R為:\n",R)
MF = np.dot(P,Q)
print("預測矩陣:\n",MF)
 
 
#下面代碼可以繪制損失函數的收斂曲線圖
n=len(result)
x=range(n)
plt.plot(x, result,color='b',linewidth=3)
plt.xlabel("generation")
plt.ylabel("loss")
plt.show()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM