1. 程式人生 > 實用技巧 >機器學習實戰---SVD簡化資料

機器學習實戰---SVD簡化資料

一:參考資料

(一)機器學習實戰

(二)如何讓奇異值分解(SVD)變得不“奇異”?(特別好理解SVD)

http://redstonewill.com/1529/

https://blog.csdn.net/yusisc/article/details/82216800

(三)奇異值分解(SVD)原理與在降維中的應用

(四)深入理解PCA與SVD的關係

二:推薦系統協調過濾演算法

(一)文章回顧

https://www.cnblogs.com/ssyfj/p/12951542.html

(二)另一種實現方法

import numpy as np

#一:相似度計算,傳入的都是列向量
def eulidSim(inA,inB):  #相似度
=1/(1+距離) 物品對越相似,它們的相似度值就越大。 return 1/(1+np.linalg.norm(inA-inB)) #距離按照第二正規化計算 def pearsSim(inA,inB): #皮爾遜相關係數 相似度=0.5+0.5*corrcoef if len(inA) < 3: #為啥小於3???書上說小於3的兩個向量完全相關(不應該是2嗎?) return 1 return 0.5 + 0.5*np.corrcoef(inA,inB,rowvar=0)[0][1] def cosSim(inA,inB): #餘弦相似度 num
= inA.T@inB denom = np.linalg.norm(inA)*np.linalg.norm(inB) return 0.5+0.5*(num/denom) #二:資料載入 def loadDataSet(): return np.array([[4,4,0,2,3], [4,0,0,3,3], [4,0,0,1,1], [1,1,1,2,0], [2,2,2,0,0], [
1,1,1,0,0], [5,5,5,0,0]]) #三:實現基於物品相似度的推薦引擎 #1.根據某個使用者編號和其對應的多個未評價的物品中的一個,進行估計評分值(是直接對該物品評分) def standEst(dataArr,userId,itemId,simMeas): n = dataArr.shape[1] #所有物品數目 simTotal = 0 #計算整體相似度 ratSimTotal = 0 #計算相似度作為權重,對現有另一個使用者評分加權後的評分 #迴圈所有物品 for j in range(n): userScore = dataArr[userId,j] #獲取本使用者對物品的評分 if userScore == 0: continue #如果使用者沒有評分,則不進行相似度評價 #找到一個物品,同我們指定的物品。都同時給予了評價的使用者(有無重合,有重合,才可以進行相似度計算) overLap = np.where(np.logical_and(dataArr[:,itemId],dataArr[:,j]))[0] #獲取使用者索引 if len(overLap) == 0: #無相似度 similarity = 0 else: similarity = simMeas(dataArr[overLap,itemId],dataArr[overLap,j]) #計算重合部分的相似度 simTotal += similarity ratSimTotal += similarity*userScore #進行返回 if simTotal == 0: return 0 #如果沒有找到相似物品,返回評分0即可 else: return ratSimTotal/simTotal #通過除以所有的相似度和,對上述相似度評分的乘積進行歸一化,使得最後評分在0~5之間,這些評分用來對預測值進行排序 #2.使用上面估分,進行輔助。推薦物品 def recommend(dataArr,userId,N=3,simMeas=cosSim,estMethod=standEst): #N是想要獲取的最符合的物品(估計評分最高) #操作該使用者沒有評價的物品 unratedItems = np.where(dataArr[userId] == 0)[0] if len(unratedItems) == 0: #全部評價了 print("you rated everything") return #獲取全部未評價的物品評分值 itemsScore = [] for i in unratedItems: estimatedScore = estMethod(dataArr,userId,i,simMeas) itemsScore.append((i,estimatedScore)) #傳入物品編號和評分 #返回我們想要的物品數 return sorted(itemsScore,key=lambda p:p[1],reverse=True)[:N] #獲取前N個最高評分的物品 data = loadDataSet() print(recommend(data,2))

三:使用SVD提高推薦效果

(一)不變程式碼

import numpy as np

#一:相似度計算,傳入的都是列向量
def eulidSim(inA,inB):  #相似度=1/(1+距離) 物品對越相似,它們的相似度值就越大。
    return 1/(1+np.linalg.norm(inA-inB))    #距離按照第二正規化計算

def pearsSim(inA,inB):  #皮爾遜相關係數 相似度=0.5+0.5*corrcoef
    if len(inA) < 3:    #為啥小於3???書上說小於3的兩個向量完全相關(不應該是2嗎?)
        return 1
    return 0.5 + 0.5*np.corrcoef(inA,inB,rowvar=0)[0][1]

def cosSim(inA,inB):    #餘弦相似度
    num = float(inA.T@inB)
    denom = np.linalg.norm(inA)*np.linalg.norm(inB)
    return 0.5+0.5*(num/denom)


#二:資料載入
def loadDataSet():
    return np.array([[4,4,0,2,3],
                     [4,0,0,3,3],
                     [4,0,0,1,1],
                     [1,1,1,2,0],
                     [2,2,2,0,0],
                     [1,1,1,0,0],
                     [5,5,5,0,0]])

#三:實現基於物品相似度的推薦引擎
#1.根據某個使用者編號和其對應的多個未評價的物品中的一個,進行估計評分值(是直接對該物品評分)
def standEst(dataArr,userId,itemId,simMeas):
    n = dataArr.shape[1]    #所有物品數目
    simTotal = 0    #計算整體相似度
    ratSimTotal = 0 #計算相似度作為權重,對現有另一個使用者評分加權後的評分
    #迴圈所有物品
    for j in range(n):
        userScore = dataArr[userId,j]   #獲取本使用者對物品的評分
        if userScore == 0:
            continue    #如果使用者沒有評分,則不進行相似度評價

        #找到一個物品,同我們指定的物品。都同時給予了評價的使用者(有無重合,有重合,才可以進行相似度計算)
        overLap = np.where(np.logical_and(dataArr[:,itemId],dataArr[:,j]))[0]   #獲取使用者索引

        if len(overLap) == 0:   #無相似度
            similarity = 0
        else:
            similarity = simMeas(dataArr[overLap,itemId],dataArr[overLap,j])   #計算重合部分的相似度
        simTotal += similarity
        ratSimTotal += similarity*userScore

    #進行返回
    if simTotal == 0:
        return 0    #如果沒有找到相似物品,返回評分0即可
    else:
        return ratSimTotal/simTotal #通過除以所有的相似度和,對上述相似度評分的乘積進行歸一化,使得最後評分在0~5之間,這些評分用來對預測值進行排序

#2.使用上面估分,進行輔助。推薦物品
def recommend(dataArr,userId,N=3,simMeas=cosSim,estMethod=standEst):    #N是想要獲取的最符合的物品(估計評分最高)
    #操作該使用者沒有評價的物品
    unratedItems = np.where(dataArr[userId] == 0)[0]

    if len(unratedItems) == 0:  #全部評價了
        print("you rated everything")
        return

    #獲取全部未評價的物品評分值
    itemsScore = []

    for i in unratedItems:
        estimatedScore = estMethod(dataArr,userId,i,simMeas)
        itemsScore.append((i,estimatedScore))   #傳入物品編號和評分

    #返回我們想要的物品數
    return sorted(itemsScore,key=lambda p:p[1],reverse=True)[:N]    #獲取前N個最高評分的物品

(二)SVD程式碼實現

def loadExData2():
    return  np.array([[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]])

def svdEst(dataArr,userId,itemId,simMeas):  #https://zhuanlan.zhihu.com/p/58064462
    n = dataArr.shape[1]    #獲取全部物品數量
    simTotal = 0
    ratSimTotal = 0
    #使用SVD進行分解
    #注意:python返回的sigma只有數值,不是矩陣
    U,Sigma,VT = np.linalg.svd(dataArr) #注意行為使用者,列為物品
    #建立對角矩陣
    Sig4 = np.eye(4)*Sigma[:4]  #建立對角矩陣 注意:我們選取4個最大特徵值,保持這四個特徵值的總能量>90%全部特徵總能量,使用前,先測試
    #建立低維空間,使用U特徵矩陣,降低冗餘樣本
    xformedItems = dataArr.T@U[:,:4]@np.linalg.inv(Sig4)    #現在是n,4但是後面進行轉置,變為4,n達到降低冗餘
    for j in range(n):
        userRating = dataArr[userId,j]  #獲取評分
        if userRating == 0 or j == itemId:
            continue    #使用者沒有評分,或者物品就是本身,不處理
        similarity = simMeas(np.array([xformedItems[itemId,:]]).T,np.array([xformedItems[j,:]]).T)
        print(np.array([xformedItems[itemId,:]]).T, np.array([xformedItems[j,:]]).T)
        print('the %d and %d similarity is: %f' % (itemId, j, similarity))
        #[-0.01591788 -0.39205093  0.55707516  0.04356321] [-0.0552444  -0.52034959 -0.36330956 -0.19023805]
        simTotal += similarity
        ratSimTotal += similarity*userRating #加權評分
    if simTotal == 0:
        return 0
    else:
        return ratSimTotal/simTotal

data = loadExData2()
print(recommend(data,1,estMethod=svdEst))

四:機器學習就先這樣吧,以後在使用統計學習方法回顧.....