【矩陣分解一】奇異值分解SVD(Singular Value Decomposition)

推薦場景下,矩陣分解方法:SVD、FunkSVD、BiasSVD、SVD++、ALS。

本篇內容主要介紹SVD,包含:EVD、SVD、SVD在推薦中的應用demo;

1.基於矩陣分解推薦算法的背景

矩陣分解模型在推薦系統中有非常不錯的表現,相對於傳統的協同過濾方法,它不僅能通過降維增加模型的泛化能力,也方便加入其他因素(如數據偏差、時間、隱反饋等)對問題建模,從而產生更佳的推薦結果。

先來說說矩陣分解幾個明顯的特點,它具有協同過濾的 “集體智慧”,隱語義的 “深層關係”,以及機器學習的 “以目標爲導向的有監督學習”。在瞭解了基於鄰域的協同過濾算法後,集體智慧自不必多說,我們依次從 “隱因子” 和 “有監督學習” 的角度來了解矩陣分解的基本思路。

基於矩陣分解的推薦算法的核心假設是用隱語義(隱變量)來表達用戶和物品,他們的乘積關係就成爲了原始的元素。這種假設之所以成立,是因爲我們認爲實際的交互數據是由一系列的隱變量的影響下產生的(通常隱變量帶有統計分佈的假設,就是隱變量之間,或者隱變量和顯式變量之間的關係,我們往往認爲是由某種分佈產生的。),這些隱變量代表了用戶和物品一部分共有的特徵,在物品身上表現爲屬性特徵,在用戶身上表現爲偏好特徵,只不過這些因子並不具有實際意義,也不一定具有非常好的可解釋性,每一個維度也沒有確定的標籤名字,所以纔會叫做 “隱變量”。而矩陣分解後得到的兩個包含隱變量的小矩陣,一個代表用戶的隱含特徵,一個代表物品的隱含特徵,矩陣的元素值代表着相應用戶或物品對各項隱因子的符合程度,有正面的也有負面的。

隨着人們的不斷探索和研究,衍生出了矩陣分解的一系列算法,接下來的幾篇文章,分別講講矩陣分解的幾種方法。

爲什麼要做SVD?

對於奇異值,它跟我們特徵分解中的特徵值類似,在奇異值矩陣中也是按照從大到小排列,而且奇異值的減少特別的快,在很多情況下,前10%甚至1%的奇異值的和就佔了全部的奇異值之和的99%以上的比例。也就是說,我們也可以用最大的K個的奇異值和對應的左右奇異向量來近似描述矩陣。其中K要比n小很多,也就是一個大的矩陣A可以用三個小的矩陣來表示。數學之美中有說,會減少很大的存儲資源。

K怎麼確定?

多啓發式的算法,當然,最直接的是直接用肉眼觀察。除此之外,一個典型做法是保留矩陣中90%的能量信息。具體來講,我們可以對奇異值求平方和。於是可以對奇異值的平方和累加直至總和的90%爲止。 

2.聊聊SVD--矩陣分解的方法之一

特徵值分解EVD

在討論SVD之前先討論矩陣的特徵值分解(EVD)(eigenvalue decomposition),對稱陣有一個很優美的性質:它總能相似對角化,對稱陣特徵值對應的特徵向量兩兩正交。

A = V*D* V^{T}

其中A的對稱矩陣,D是對角矩陣,對角元素是A的特徵值(幾何意義:變換時的縮放),V的列是A的特徵向量(幾何意義:特徵向量經過矩陣A的變換,只進行縮放(特徵值的大小),不改變其方向),特徵向量兩兩正交,可以理解爲一個高維的空間。

我們看看上面的公式怎麼得來的:

設特徵值爲\lambda,單位特徵向量爲x,那麼對於所有的特徵值和單位特徵向量都有:Ax = \lambda x,寫成矩陣的形式:A*U = U * \Lambda,所以可得到A的特徵值分解(由於對稱陣特徵向量兩兩正交,所以U爲正交陣,正交陣的逆矩陣等於其轉置):

A= U* \Lambda *U^{-1} = U* \Lambda *U^{T}

A不是滿秩的話,那麼就是說對角陣的對角線上元素存在0,這時候就會導致維度退化,這樣就會使映射後的向量落入m維空間的子空間中。

svd是上面這個式子的演化,放鬆了對矩陣A的要求,不要求A爲對稱矩陣。

(在svd中,有左右兩個矩陣,那麼帶有隱語義信息的向量使用哪一個矩陣?這兩個矩陣分別代表什麼?user和item表示有差別嗎?)

svd分解

上面的特徵值分解的A矩陣是對稱陣,根據EVD可以找到一個(超)矩形使得變換後還是(超)矩形,也即A可以將一組正交基映射到另一組正交基!那麼現在來分析:對任意M*N的矩陣,能否找到一組正交基使得經過它變換後還是正交基?答案是肯定的,它就是SVD分解的精髓所在。

現在假設存在M*N矩陣A,事實上,A矩陣將n維空間中的向量映射到k(k<=m)維空間中,k=Rank(A)。現在的目標就是:在n維空間中找一組正交基,使得經過A變換後還是正交的。

如果A的特徵值中,部分爲0,形如下面:

可以得到A矩陣的奇異值分解,如下所示:

其中A就是被分解的矩陣,A矩陣是m* n維的,U是一個正交矩陣m * m維的,\sum是一個對角矩陣,m* n維,V也是一個正交矩陣n* n維的。(幾何角度理解,實質是一個矩陣變換的操作,U中的列向量原始空間中的座標軸向量,通過變換,將其變換到V空間中,變換的尺度是\sum\sum中的元素大小,表示V空間中,對應列向量的重要程度。)

對應到推薦場景中,分解得到的三個矩陣含義:

U:user的語義向量,每一行代表一個用戶向量。

\sum:表示user和item的相關性。

V:item的語義向量,每一列代表一個item向量。

奇異值

\sum中的對角元素稱爲奇異值,並且按照從大到小排列,U矩陣的列稱爲矩陣A的左奇異向量(left singular vectors),V中的列稱爲矩陣A的右奇異向量(right singular vectors)。一定要區別異常值和奇異值,概念上貌似差不多,但是意義上相差萬里。

EVD & SVD 區別

1)EVD針對對角化矩陣而言,而SVD更加通用,對於任意矩陣m*n,都可以進行分解。

2)矩陣乘法對應了一個變換,一個矩陣乘以一個向量後得到新的向量,相當於這個向量變成了另一個方向或者長度都不同的新向量。如果一個矩陣與某一個向量或者多個向量相乘,該向量只發生了縮放變換,不對該向量產生旋轉的效果,則稱該向量爲這個矩陣的特徵向量,伸縮比例是特徵值。而奇異值分解的使用範圍更廣泛,將M從V向量空間旋轉到U空間(M右邊乘以了V矩陣,也就是從V空間做變換,旋轉縮放到U空間),不僅僅發生了縮放,還有旋轉,旋轉的時候,空間維度會發生變化,從m變化到n。可以認爲這是EVD和SVD的本質區別。

用途(爲什麼要做矩陣分解)

1)SVD可用於矩陣降維。我們可以利用SVD來逼近矩陣並從中提取重要的特徵。再通過保留矩陣80%-90%的能量,又或者只保留前2千-3千的奇異值(當奇異值上萬時),來實現得到重要的特徵和去除其餘噪聲。

2)降噪。多應用在圖像領域。可以看[3]中的例子。

3)數據分析。我們蒐集的數據中總是存在噪聲:無論採用的設備多精密,方法有多好,總是會存在一些誤差的。如果你們還記得上文提到的,大的奇異值對應了矩陣中的主要信息的話,運用SVD進行數據分析,提取其中的主要部分的話,還是相當合理的。比如得到兩個奇異值σ1 = 6.04,σ2 = 0.22,由於第一個奇異值遠比第二個要大,數據中有包含一些噪聲,第二個奇異值在原始矩陣分解相對應的部分可以忽略。經過SVD分解後,保留了主要樣本點。就保留主要樣本數據來看,該過程跟PCA( principal component analysis)技術有一些聯繫,PCA也使用了SVD去檢測數據間依賴和冗餘信息.

4)用於推薦領域。

數據集中行代表用戶user,列代表物品item,其中的值代表用戶對物品的打分。基於SVD的優勢在於:用戶的評分數據是稀疏矩陣,可以用SVD將原始數據映射到低維空間中,然後計算物品item之間的相似度,可以節省計算資源。

整體思路:先找到用戶沒有評分的物品,然後再經過SVD“壓縮”後的低維空間中,計算未評分物品與其他物品的相似性,得到一個預測打分,再對這些物品的評分從高到低進行排序,返回前N個物品推薦給用戶。

主要分爲5步驟:

第1部分:加載測試數據集;

第2部分:定義三種計算相似度的方法;

第3部分:通過計算奇異值平方和的百分比來確定將數據降到多少維才合適,返回需要降到的維度;

第4部分:在已經降維的數據中,基於SVD對用戶未打分的物品進行評分預測,返回未打分物品的預測評分值;

第5部分:產生前N個評分值高的物品,返回物品編號以及預測評分值。

說說第3部分:很多時候,維度是隨便定義,這裏給出了確定K的理論依據,如果你看到這篇博客,牢記確定K的依據在此。維度越大包含的信息越多,資源和計算時間也耗費比較多;維度較小,丟失一部分信息,信息更加精煉,會去掉部分噪聲信息,資源和時間耗費較少,這裏確定時要有一個取捨了。(現在存在一個問題,MF(ALS)中的K是怎麼確定的吶?依據是什麼?依稀記得,論文中沒有給出精確的確定方法,只說可大可小。工作的時候,落地了MF算法,確定維度也是很隨意,根據公司組件能容納接受的最大維度來確定K值,現在思考一下,感覺缺失理論依據。把第3部分的內容拿出來作爲理論依據,或許更靠譜)

SVD的優缺點

優點:簡化數據,去除噪聲,提高算法的結果。

缺點:數據的轉換可能難以理解。

適用數據類型:數值型數據。

求解方法

關係式的右邊描述了關係式左邊的特徵值分解。於是:
V的列向量(右奇異向量)是MTM的特徵向量。
U 的列向量(左奇異向量)是MMT 的特徵向量。
Σ的非零對角元(非零奇異值)是MTM或者MMT的非零特徵值的平方根。

數學之美中p168頁面:

3.用於推薦場景的代碼demo

目的:由一個稀疏的評分矩陣推算出其中的空缺分數。舉個例子,在電影評分中,我們的目的是得到用戶對未評價電影的分數,而這種user-Item的評分矩陣中,用戶對Item的分數是沒有直接關係的,我們需要尋找一種隱空間,使得將用戶和Item聯繫起來。比如我們無法得知user1對《利刃出鞘》這部電影的分數,但是我們可以通過用戶的歷史信息(即用戶對別的電影的分數)得到用戶對“懸疑”類電影的愛好程度,我們也可以得到某個電影的“懸疑類”的程度有多大,這樣,我們就可以將這倆個關係聯繫到一起了。

一句話:通過用戶對電影A的有評分,對B沒有評分,那麼用戶喜歡B嗎?從SVD得到的item向量中,通過計算A與B的相似度,能得到用戶對B的喜歡程度。代碼:ratSimTotal+=similarity*userRating,ratSimTotal表示對B的評分。

#coding=utf-8
from numpy import *
from numpy import linalg as la

'''加載測試數據集'''
def loadExData():
    return mat([[0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 5],
           [0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 3],
           [0, 0, 0, 0, 4, 0, 0, 1, 0, 4, 0],
           [3, 3, 4, 0, 0, 0, 0, 2, 2, 0, 0],
           [5, 4, 5, 0, 0, 0, 0, 5, 5, 0, 0],
           [0, 0, 0, 0, 5, 0, 1, 0, 0, 5, 0],
           [4, 3, 4, 0, 0, 0, 0, 5, 5, 0, 1],
           [0, 0, 0, 4, 0, 4, 0, 0, 0, 0, 4],
           [0, 0, 0, 2, 0, 2, 5, 0, 0, 1, 2],
           [0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0],
           [1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0]])

'''以下是三種計算相似度的算法,分別是歐式距離、皮爾遜相關係數和餘弦相似度,
注意三種計算方式的參數inA和inB都是列向量'''
def ecludSim(inA,inB):
    return 1.0/(1.0+la.norm(inA-inB))  #範數的計算方法linalg.norm(),這裏的1/(1+距離)表示將相似度的範圍放在0與1之間

def pearsSim(inA,inB):
    if len(inA)<3: return 1.0
    return 0.5+0.5*corrcoef(inA,inB,rowvar=0)[0][1]  #皮爾遜相關係數的計算方法corrcoef(),參數rowvar=0表示對列求相似度,這裏的0.5+0.5*corrcoef()是爲了將範圍歸一化放到0和1之間

def cosSim(inA,inB):
    num=float(inA.T*inB)
    denom=la.norm(inA)*la.norm(inB)
    return 0.5+0.5*(num/denom) #將相似度歸一到0與1之間

'''按照前k個奇異值的平方和佔總奇異值的平方和的百分比percentage來確定k的值,
後續計算SVD時需要將原始矩陣轉換到k維空間'''
def sigmaPct(sigma,percentage):
    sigma2=sigma**2 #對sigma求平方
    sumsgm2=sum(sigma2) #求所有奇異值sigma的平方和
    sumsgm3=0 #sumsgm3是前k個奇異值的平方和
    k=0
    for i in sigma:
        sumsgm3+=i**2
        k+=1
        if sumsgm3>=sumsgm2*percentage:
            return k

'''函數svdEst()的參數包含:數據矩陣、用戶編號、物品編號和奇異值佔比的閾值,
數據矩陣的行對應用戶,列對應物品,函數的作用是基於item的相似性對用戶未評過分的物品進行預測評分'''
def svdEst(dataMat,user,simMeas,item,percentage):
    n=shape(dataMat)[1]
    simTotal=0.0;ratSimTotal=0.0
    u,sigma,vt=la.svd(dataMat)
    k=sigmaPct(sigma,percentage) #確定了k的值
    sigmaK=mat(eye(k)*sigma[:k])  #構建對角矩陣
    xformedItems=dataMat.T*u[:,:k]*sigmaK.I  #根據k的值將原始數據轉換到k維空間(低維),xformedItems表示物品(item)在k維空間轉換後的值
    for j in range(n):
        userRating=dataMat[user,j]
        if userRating==0 or j==item:continue
        similarity=simMeas(xformedItems[item,:].T,xformedItems[j,:].T) #計算物品item與物品j之間的相似度
        simTotal+=similarity #對所有相似度求和
        ratSimTotal+=similarity*userRating #用"物品item和物品j的相似度"乘以"用戶對物品j的評分",並求和
    if simTotal==0:return 0
    else:return ratSimTotal/simTotal #得到對物品item的預測評分

'''函數recommend()產生預測評分最高的N個推薦結果,默認返回5個;
參數包括:數據矩陣、用戶編號、相似度衡量的方法、預測評分的方法、以及奇異值佔比的閾值;
數據矩陣的行對應用戶,列對應物品,函數的作用是基於item的相似性對用戶未評過分的物品進行預測評分;
相似度衡量的方法默認用餘弦相似度'''
def recommend(dataMat,user,N=5,simMeas=cosSim,estMethod=svdEst,percentage=0.9):
    unratedItems=nonzero(dataMat[user,:].A==0)[1]  #建立一個用戶未評分item的列表
    if len(unratedItems)==0:return 'you rated everything' #如果都已經評過分,則退出
    itemScores=[]
    for item in unratedItems:  #對於每個未評分的item,都計算其預測評分
        estimatedScore=estMethod(dataMat,user,simMeas,item,percentage)
        itemScores.append((item,estimatedScore))
    itemScores=sorted(itemScores,key=lambda x:x[1],reverse=True)#按照item的得分進行從大到小排序
    return itemScores[:N]  #返回前N大評分值的item名,及其預測評分值

將文件命名爲svd2.py,在python提示符下輸入:

>>>import svd2
>>>testdata=svd2.loadExData()
>>>svd2.recommend(testdata,1,N=3,percentage=0.8)#對編號爲1的用戶推薦評分較高的3件商品

最後解析下怎麼生成item的k維向量:

    xformedItems=dataMat.T*u[:,:k]*sigmaK.I

假設:dataMat=[m,n],這裏的m表示用戶的維度,n表示item維度;他的轉置data.Mat.T=[n,m],u= [m,k],sigmaK = [k,n],這三個矩陣相乘得到xformaedItems=[k, n],其中每一列表示一個商品的向量,這裏k <<< m。

其他:

這裏使用到得SVD的思想只是說任何一個矩陣均可以分解成兩個矩陣相乘的形式(SVD是三個,但也可以合併倆個得到兩個矩陣,但是合併之後的意義,目前我還不是很理解,邊學習邊記錄~~),這兩個子矩陣分別代表了用戶的偏好程度和電影的成分程度,將這兩個矩陣相乘即可得到用戶對電影的評分矩陣。

 

參考:

1.矩陣分解模型https://iamhere1.github.io/2018/01/03/mf/

2.盧神的博客 https://lumingdong.cn/recommendation-algorithm-based-on-matrix-decomposition.html

3.從集合角度理解svd http://blog.chinaunix.net/uid-20761674-id-4040274.html

4.論文 http://www-users.math.umn.edu/~lerman/math5467/svd.pdf

5.EVD&SVDhttps://blog.csdn.net/zhongkejingwang/article/details/43053513

6.https://www.jianshu.com/p/9613b26c8b03

7.論文 Matrix Factorization Techniques for Recommender Systems

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