日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

机器学习SVD【二】

發布時間:2025/3/17 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 机器学习SVD【二】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本篇的數據和代碼參見:https://github.com/stonycat/ML-in-Action?
一、開篇:簡述SVD應用?
利用SVD實現,我們能夠用小得多的數據集來表示原始數據集。這樣做,實際上是去除了噪聲和冗余信息。簡而言之,SVD是一種從大量數據中提取主要關鍵數據的方法。

下面介紹幾種應用場景:?
1、隱性語義索引?
最早的SVD應用之一就是信息檢索。我們稱利用SVD的方法為隱性語義索引(LatentSemantic Indexing,LSI)或隱性語義分析(Latent Semantic Analysis,LSA)。在LSI中,一個矩陣是由文檔和詞語組成的。應用SVD時,構建的SVD奇異值代表了文章的主題或者主要概念。?
當我們查找一個詞時,其同義詞所在的文檔可能并不會匹配上。如果我們從上千篇相似的文檔中抽取出概念,那么同義詞就會映射為同一概念。

2、推薦系統?
簡單版本的推薦系統能夠計算項或者人之間的相似度。更先進的方法則先利用SVD從數據中構建一個主題空間,然后再在該空間下計算其相似度。

SVD是矩陣分解的一種類型,而矩陣分解是將數據矩陣分解為多個獨立部分的過程。

二、矩陣分解?
很多情況下,數據中的一小段攜帶了數據集中的大部分信息,其他信息則要么是噪聲,要么就是毫不相關的信息。?
在線性代數中還有很多矩陣分解技術。矩陣分解可以將原始矩陣表示成新的易于處理的形式,這種新形式是兩個或多個矩陣的乘積。?
不同的矩陣分解技術具有不同的性質,其中有些更適合于某個應用,有些則更適合于其他應用。最常見的一種矩陣分解技術就是SVD。公式如下:

Datam×n=Um×m?Σm×n?VTn×nDatam×n=Um×m?Σm×n?Vn×nT
上述分解中會構建出一個矩陣 Σ ,該矩陣只有對角元素,其他元素均為0。另一個慣例就是,Σ 的對角元素是從大到小排列的。這些對角元素稱為 奇異值(Singular Value) ,它們對應了原始數據集矩陣 Data 的奇異值。奇異值和特征值是有關系的。這里的奇異值就是矩陣 Data?DataTData?DataT ?特征值的平方根。

科學和工程中,一直存在這樣一個普遍事實:在某個奇異值的數目( r 個)之后,其他的奇異值都置為0。這就意味著數據集中僅有 r個重要特征,而其余特征則都是噪聲或冗余特征。

三、利用 Python 實現 SVD?
NumPy有一個稱為linalg的線性代數工具箱。接下來,我們了解一下如何利用該工具箱實現如下矩陣的SVD處理:?

Sigma為了方便僅返回對角元素。?
建立一個新文件 svdRec.py 并加入如下代碼:

def loadExData():return [[0, 0, 0, 2, 2],[0, 0, 0, 3, 3],[0, 0, 0, 1, 1],[1, 1, 1, 0, 0],[2, 2, 2, 0, 0],[5, 5, 5, 0, 0],[1, 1, 1, 0, 0]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

測試:

>>> import svdRec >>> Data=svdRec.loadExData() >>> U,Sigma,VT=linalg.svd(Data) >>> Sigma array([ 9.64365076e+00, 5.29150262e+00, 8.36478329e-16,6.91811207e-17, 3.76946717e-34])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

前 3 個數值比其他的值大了很多(如果你的最后兩個值的結果與這里的結果稍有不同,也不必擔心。它們太小了,所以在不同機器上產生的結果就可能會稍有不同,但是數量級應該和這里的結果差不多)。于是,我們就可以將最后兩個值去掉了。數據表示為:?

Datam×n=Um×3?Σ3×3?VT3×nDatam×n=Um×3?Σ3×3?V3×nT

我們是如何知道僅需保留前 3 個奇異值的呢?確定要保留的奇異值的數目有很多啟發式的策略,其中一個典型的做法就是保留矩陣中?90%?的能量信息。我們將所有的奇異值求其平方和,將平方和累加到總值的 90% 為止。

另一個啟發式策略就是,當矩陣上有上萬的奇異值時,那么就保留前面的 2000 或 3000 個。盡管后一種方法不太優雅,但是在實際中更容易實施。

現在我們已經通過三個矩陣對原始矩陣進行了近似。我們可以用一個小很多的矩陣來表示一個大矩陣。有很多應用可以通過 SVD 來提升性能。下面我們將討論一個比較流行的 SVD 應用的例子 —— 推薦引擎。

四、基于協同過濾的推薦引擎?
協同過濾( collaborative filtering )是通過將用戶和其他用戶的數據進行對比來實現推薦的,唯一所需要的數學方法就是相似度的計算。

1、相似度計算?
利用用戶對它們的意見來計算相似度:這就是協同過濾中所使用的方法。它并不關心物品的描述屬性,而是嚴格地按照許多用戶的觀點來計算相似度。

我們希望,相似度值在 0 到 1 之間變化,并且物品對越相似,它們的相似度值也就越大。我們可以用“相似度 =1/(1+ 距離 ) ”這樣的算式來計算相似度。當距離為 0 時,相似度為 1.0 。如果距離真的非常大時,相似度也就趨近于 0 。?
1-距離采用歐式距離來計算(計算平方和)。

2-第二種計算距離的方法是皮爾遜相關系數( Pearson correlation )。?
該方法相對于歐氏距離的一個優勢在于,它對用戶評級的量級并不敏感。比如某個狂躁者對所有物品的評分都是 5 分,而另一個憂郁者對所有物品的評分都是 1 分,皮爾遜相關系數會認為這兩個向量是相等的。在 NumPy 中,皮爾遜相關系數的計算是由函數 corrcoef() 進行的,后面我們很快就會用到它了。皮爾遜相關系數的取值范圍從? 1 到 +1 ,我們通過?0.5 + 0.5*corrcoef()?這個函數計算,并且把其取值范圍歸一化到 0 到 1 之間。

3-余弦相似度 ( cosine similarity )?
其計算的是兩個向量夾角的余弦值。如果夾角為 90 度,則相似度為 0 ;如果兩個向量的方向相同,則相似度為 1.0 。

cosΘ=A?BABcosΘ=A?B‖A‖‖B‖
其中 AB‖A‖‖B‖ 為A、B的2范數。你可以定義向量的任一范數,但是如果不指定范數階數,則都假設為 2 范數。

from numpy import * from numpy import linalg as la #相似度1:歐式距離 def ecludSim(inA,inB):return 1.0/(1.0 + la.norm(inA - inB)) #相似度2:威爾遜距離 def pearsSim(inA,inB):if len(inA) < 3 : return 1.0return 0.5+0.5*corrcoef(inA, inB, rowvar = 0)[0][1] #相似度3:余弦 def cosSim(inA,inB):num = float(inA.T*inB)denom = la.norm(inA)*la.norm(inB)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
#歐式距離 >>> myMat=mat(svdRec.loadExData()) >>> svdRec.ecludSim(myMat[:,0],myMat[:,4]) 0.12973190755680383 >>> svdRec.ecludSim(myMat[:,0],myMat[:,0]) 1.0 #威爾遜相關系數 >>> svdRec.pearsSim(myMat[:,0],myMat[:,4]) 0.20596538173840329 >>> svdRec.pearsSim(myMat[:,0],myMat[:,0]) 1.0 #余弦相似度 >>> svdRec.cosSim(myMat[:,0],myMat[:,4]) 0.5 >>> svdRec.cosSim(myMat[:,0],myMat[:,0]) 1.0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2、基于物品的相似度還是基于用戶的相似度??
?
上圖:行與行之間比較的是基于用戶的相似度,列與列之間比較的則是基于物品的相似度。到底使用哪一種相似度呢??
這取決于用戶或物品的數目

基于物品相似度計算的時間會隨物品數量的增加而增加,基于用戶的相似度計算的時間則會隨用戶數量的增加而增加。?
如果用戶的數目很多,那么我們可能傾向于使用基于物品相似度的計算方法。對于大部分產品導向的推薦引擎而言,用戶的數量往往大于物品的數量,即購買商品的用戶數會多于出售的商品種類。

3、推薦引擎的評價?
如何對推薦引擎進行評價呢?此時,我們既沒有預測的目標值,也沒有用戶來調查他們對預測的滿意程度。這里我們就可以采用前面多次使用的交叉測試的方法。具體的做法就是,我們將某些已知的評分值去掉,然后對它們進行預測,最后計算預測值和真實值之間的差異。?
通常用于推薦引擎評價的指標是稱為最小均方根誤差( Root Mean Squared Error , RMSE )的指標,它首先計算均方誤差的平均值然后取其平方根。

五、示例:餐館菜肴推薦引擎?
構建一個基本的推薦引擎,它能夠尋找用戶沒有嘗過的菜肴。然后,通過 SVD 來減少特征空間并提高推薦的效果。這之后,將程序打包并通過用戶可讀的人機界面提供給人們使用。

(1) 尋找用戶沒有評級的菜肴,即在用戶-物品矩陣中的 0 值;?
(2) 在用戶沒有評級的所有物品中,對每個物品預計一個可能的評級分數。這就是說,我們?
認為用戶可能會對物品的打分(這就是相似度計算的初衷);?
(3) 對這些物品的評分從高到低進行排序,返回前N個物品。

下述代碼:遍歷數據行中的每個物品。如果某個物品評分值為 0 ,就意味著用戶沒有對該物品評分,跳過了這個物品。該循環大體上是對用戶評過分的每個物品進行遍歷,并將它和其他物品進行比較。

但是如果存在重合的物品,則基于這些重合物品計算相似度。隨后,相似度會不斷累加,每次計算時還考慮相似度和當前用戶評分的乘積。最后,通過除以所有的評分總和,對上述相似度評分的乘積進行歸一化。這就可以使得最后的評分值在 0 到 5 之間,而這些評分值則用于對預測值進行排序。

#遍歷 計算相似度 def standEst(dataMat, user, simMeas, item):#數據矩陣、用戶編號、相似度計算方法和物品編號n = shape(dataMat)[1]simTotal = 0.0;ratSimTotal = 0.0for j in range(n):userRating = dataMat[user, j]if userRating == 0: continue#尋找兩個用戶都做了評價的產品overLap = nonzero(logical_and(dataMat[:, item].A > 0, dataMat[:, j].A > 0))[0]if len(overLap) == 0:similarity = 0else:#存在兩個用戶都評價的產品 計算相似度similarity = simMeas(dataMat[overLap, item], dataMat[overLap, j])print ('the %d and %d similarity is: %f' % (item, j, similarity))simTotal += similarity #計算每個用戶對所有評價產品累計相似度ratSimTotal += similarity * userRating #根據評分計算比率if simTotal == 0:return 0else:return ratSimTotal / simTotal#推薦實現:recommend() 產生了最高的 N 個推薦結果 def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):unratedItems = nonzero(dataMat[user, :].A == 0)[1] #尋找用戶未評價的產品if len(unratedItems) == 0: return ('you rated everything')itemScores = []for item in unratedItems:estimatedScore = estMethod(dataMat, user, simMeas, item)#基于相似度的評分itemScores.append((item, estimatedScore))return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[:N]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

recommend()函數在所有的未評分物品上進行循環。對每個未評分物品,則通過調用standEst() 來產生該物品的預測得分。該物品的編號和估計得分值會放在一個元素列表itemScores 中。最后按照估計得分,對該列表進行排序并返回。

測試:

>>> reload(svdRec) <module 'svdRec' from '/home/zq/Git_zq/ML-in-Action-Code-and-Note/ch14/svdRec.py'> >>> myMat=mat(svdRec.loadExData()) >>> myMat[0,1]=myMat[0,0]=myMat[1,0]=myMat[2,0]=4 >>> myMat[3,3]=2 >>> myMat matrix([[4, 4, 0, 2, 2],[4, 0, 0, 3, 3],[4, 0, 0, 1, 1],[1, 1, 1, 2, 0],[2, 2, 2, 0, 0],[5, 5, 5, 0, 0],[1, 1, 1, 0, 0]]) >>> svdRec.recommend(myMat,2) the 1 and 0 similarity is: 1.000000 the 1 and 3 similarity is: 0.928746 the 1 and 4 similarity is: 1.000000 the 2 and 0 similarity is: 1.000000 the 2 and 3 similarity is: 1.000000 the 2 and 4 similarity is: 0.000000 [(2, 2.5), (1, 2.0243290220056256)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

這表明了用戶 2 (由于我們從 0 開始計數,因此這對應了矩陣的第 3 行)對物品 2 的預測評分值為 2.5 ,對物品 1 的預測評分值為 2.05 。

下面利用 SVD 提高推薦的效果

>>> from numpy import linalg as la >>> U,Sigma,VT=la.svd(mat(svdRec.loadExData2())) >>> Sigma array([ 15.77075346, 11.40670395, 11.03044558, 4.84639758,3.09292055, 2.58097379, 1.00413543, 0.72817072,0.43800353, 0.22082113, 0.07367823]) >>> Sig2=Sigma**2 #計算平方和 >>> sum(Sig2) 541.99999999999955 >>> sum(Sig2)*0.9 #取前90% 487.79999999999961 >>> sum(Sig2[:3]) #>90% SVD取前三個特征值 500.50028912757932
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

下述程序中包含有一個函數 svdEst() 。在 recommend() 中,這個函數用于替換對 standEst() 的調用,該函數對給定用戶給定物品構建了一個評分估計值。

#利用SVD def svdEst(dataMat, user, simMeas, item):n = shape(dataMat)[1]simTotal = 0.0;ratSimTotal = 0.0U, Sigma, VT = la.svd(dataMat) #不同于stanEst函數,加入了SVD分解Sig4 = mat(eye(4) * Sigma[:4]) # 建立對角矩陣xformedItems = dataMat.T * U[:, :4] * Sig4.I #降維:變換到低維空間#下面依然是計算相似度,給出歸一化評分for j in range(n):userRating = dataMat[user, j]if userRating == 0 or j == item: continuesimilarity = simMeas(xformedItems[item, :].T, xformedItems[j, :].T)print ('the %d and %d similarity is: %f' % (item, j, similarity))simTotal += similarityratSimTotal += similarity * userRatingif simTotal == 0:return 0else:return ratSimTotal / simTotal
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
>>> svdRec.recommend(myMat,1,estMethod=svdRec.svdEst) the 1 and 0 similarity is: 0.498142 the 1 and 3 similarity is: 0.498131 the 1 and 4 similarity is: 0.509974 the 2 and 0 similarity is: 0.552670 the 2 and 3 similarity is: 0.552976 the 2 and 4 similarity is: 0.217301 [(2, 3.4177569186592378), (1, 3.3307171545585641)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

構建推薦引擎面臨的挑戰

SVD 分解可以在程序調入時運行一次。在大型系統中, SVD 每天運行一次或者其頻率更低,并且還要離線運行。?
1-推薦引擎中還存在其他很多規模擴展性的挑戰性問題,比如矩陣的表示方法。在上面給出的例子中有很多 0 ,實際系統中 0 的數目更多。也許,我們可以通過只存儲非零元素來節省內存和計算開銷?

2-一個潛在的計算資源浪費則來自于相似度得分。在我們的程序中,每次需要一個推薦得分時,都要計算多個物品的相似度得分,這些得分記錄的是物品之間的相似度。因此在需要時,這些記錄可以被另一個用戶重復使用。在實際中,另一個普遍的做法就是離線計算并保存相似度得分。

3-推薦引擎面臨的另一個問題就是如何在缺乏數據時給出好的推薦。這稱為冷啟動 ( cold-start )問題,冷啟動問題的解決方案,就是將推薦看成是搜索問題。?
為了將推薦看成是搜索問題,我們可能要使用所需要推薦物品的屬性。在餐館菜肴的例子中,我們可以通過各種標簽來標記菜肴,比如素食、美式 BBQ 、價格很貴等。同時,我們也可以將這些屬性作為相似度計算所需要的數據,這被稱為基于內容( content-based )的推薦。可能,基于內容的推薦并不如我們前面介紹的基于協同過濾的推薦效果好,但我們擁有它,這就是個良好的開始。

六、示例:基于 SVD 的圖像壓縮?
在代碼庫中,我們包含了一張手寫的數字圖像,該圖像在第 2 章使用過。原始的圖像大小是 32×32=1024 像素,我們能否使用更少的像素來表示這張圖呢?如果能對圖像進行壓縮,那么就可以節省空間或帶寬開銷了。我們可以使用 SVD 來對數據降維,從而實現圖像的壓縮。

#實例:SVD實現圖像壓縮#打印矩陣。由于矩陣包含了浮點數,因此必須定義淺色和深色。 def printMat(inMat, thresh=0.8):for i in range(32):for k in range(32):if float(inMat[i,k]) > thresh:print 1,else: print 0,print ('')#壓縮 def imgCompress(numSV=3, thresh=0.8):myl = []for line in open('0_5.txt').readlines():newRow = []for i in range(32):newRow.append(int(line[i]))myl.append(newRow)myMat = mat(myl)print ("****original matrix******")printMat(myMat, thresh)U,Sigma,VT = la.svd(myMat) #SVD分解得到特征矩陣SigRecon = mat(zeros((numSV, numSV))) #初始化新對角矩陣for k in range(numSV):#構造對角矩陣,將特征值填充到對角線SigRecon[k,k] = Sigma[k]reconMat = U[:,:numSV]*SigRecon*VT[:numSV,:]#降維print ("****reconstructed matrix using %d singular values******" % numSV)printMat(reconMat, thresh)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

imgCompress()函數基于任意給定的奇異值數目來重構圖像。該函數構建了一個列表,然后打開文本文件,讀入字符。?
接下來就開始對原始圖像進行SVD分解并重構圖像。在程序中,通過將 Sigma 重新構成 SigRecon 來實現這一點。 Sigma 是一個對角矩陣,因此需要建立一個全0矩陣,然后將前面的那些奇異值填充到對角線上。最后,通過截斷的 U 和 V T 矩陣,用 SigRecon 得到重構后的矩陣,該矩陣通過 printMat() 函數輸出。

小結?
VD 是一種強大的降維工具,我們可以利用 SVD 來逼近矩陣并從中提取重要特征。通過保留矩陣 80% ~ 90% 的能量,就可以得到重要的特征并去掉噪聲。

在大規模數據集上, SVD 的計算和推薦可能是一個很困難的工程問題。通過離線方式來進行SVD 分解和相似度計算,是一種減少冗余計算和推薦所需時間的辦法。?
在下一章中,我們將介紹在大數據集上進行機器學習的一些工具。

總結

以上是生活随笔為你收集整理的机器学习SVD【二】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。