天天看點

PYTHON機器學習實戰——SVD奇異值分解 資料降維PYTHON機器學習實戰——SVD奇異值分解 資料降維

PYTHON機器學習實戰——SVD奇異值分解 資料降維

博文末尾支援二維碼贊賞哦  

#-*- coding:utf-8 -*-
#!/usr/bin/python
'''
奇異值分解 Singular  Value  Decomposion, SVD 
樣本資料矩陣 分解得到其奇異值矩陣
'''
# 測試
# 商品推薦
# import svdRec as svd    svd.recommend_test()
# 奇異值分解重構 圖像壓縮
# import svdRec as svd    svd.imgCompress()   svd.imgCompress(numSV=2) 
from numpy import *
from numpy import linalg as la

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

#相似度 距離越近相似度越高,距離越遠相似度越低

# 歐式距離計算的相似度            1~0之間  
def ecludSim(inA,inB):
    return 1.0/(1.0 + la.norm(inA - inB)) # linalg.norm(計算2階範數)
# 皮爾遜相關系數 距離 計算的相似度 1~0之間  
def pearsSim(inA,inB):
    if len(inA) < 3 : return 1.0  # corrcoef() 在 -1 ~ 1之間
    return 0.5+0.5*corrcoef(inA, inB, rowvar = 0)[0][1]
# 餘弦相似度 距離  計算相似度
def cosSim(inA,inB):
    num = float(inA.T*inB)  # 向量 A*B
    denom = la.norm(inA)*la.norm(inB)# 向量A的模(2階範數) * 向量B的模(2階範數)
    return 0.5+0.5*(num/denom) # 向量A 與 向量B 的家教餘弦 A*B / (||A||*||B||) 範圍在-1~1

# 标準相似度方法 估計 商品評價
# 使用者對各個物品評價矩陣間的相似性 
#          資料矩陣 使用者編号  相似度計算方法  物品編号
def standEst(dataMat, user, simMeas, item):
    n = shape(dataMat)[1] # 列次元 物品數量
    simTotal = 0.0; ratSimTotal = 0.0 # 變量初始化
    for 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 = 0 # 若同時評價了的使用者數量為零,則相似性為0
        else: similarity = simMeas(dataMat[overLap,item],\
                                   dataMat[overLap,j])# 計算 共同評價了的評價矩陣之間的 相似性
        print '物品 %d 和 %d 的相似性為: %f' % (item, j, similarity) # 兩種物品間的相似性
        simTotal += similarity # 總的相似性
        ratSimTotal += similarity * userRating # 選取的物品和各個物品相似性乘上 使用者對物品的 評價權重
    if simTotal == 0: return 0
    else: return ratSimTotal/simTotal

# 基于 矩陣奇異值分解轉換 的 商品評價估計
#       資料集矩陣  使用者   相似性方法  物品辨別  
def svdEst(dataMat, user, simMeas, item):
    n = shape(dataMat)[1] # 物品種類資料
    simTotal = 0.0; ratSimTotal = 0.0 # 相似性總和 變量初始化
    U,Sigma,VT = la.svd(dataMat) # 資料集矩陣 奇異值分解  傳回的Sigma 僅為對角線上的值
    Sig4 = mat(eye(4)*Sigma[:4]) # 前四個已經包含了 90%的能力了,轉化成對角矩陣
    # 計算能量 Sigma2 = Sigma**2  energy=sum(Sigma2)   energy90= energy*0.9   energy4 = sum(Sigma2[:4])
    xformedItems = dataMat.T * U[:,:4] * Sig4.I  # 将資料轉換到低維空間
    for j in range(n):
        userRating = dataMat[user,j]
        if userRating == 0 or j==item: continue # 跳過其他未評價的商品
        similarity = simMeas(xformedItems[item,:].T,\
                             xformedItems[j,:].T)# 計算 svd分解 轉換過後矩陣的相似度
        print '物品 %d 和 %d 的相似性為: %f' % (item, j, similarity)
        simTotal += similarity
        ratSimTotal += similarity * userRating
    if simTotal == 0: return 0
    else: return ratSimTotal/simTotal

# 預測 使用者評級較高的 前幾種物品
#              資料集矩陣 使用者 推薦物品數量  相似性函數  估計方法
def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):
    unratedItems = nonzero(dataMat[user,:].A==0)[1]          # 為0的表示未評價的物品
    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]# 逆序 排序 前N個預測評價最高的未評價的商品

# 測試
def recommend_test():
    mymat1 = mat(loadExData())
    mymat2 = mat(loadExData2())
    print "矩陣1:"
    print mymat1
    print '标準推薦方法:'
    print '餘弦相似度,'
    print recommend(mymat1,2)
    print '歐式距離相似度,'
    print recommend(mymat1,2,simMeas=ecludSim)
    print '皮爾遜相似度,'
    print recommend(mymat1,2,simMeas=pearsSim)
    print '奇異值分解推薦方法:'
    print '餘弦相似度,'
    print recommend(mymat1,2,estMethod=svdEst)
    print '歐式距離相似度,'
    print recommend(mymat1,2,simMeas=ecludSim,estMethod=svdEst)
    print '皮爾遜相似度,'
    print recommend(mymat1,2,simMeas=pearsSim,estMethod=svdEst)
    print "矩陣2:"
    print mymat2
    print '标準推薦方法:'
    print '餘弦相似度,'
    print recommend(mymat2,2)
    print '歐式距離相似度,'
    print recommend(mymat2,2,simMeas=ecludSim)
    print '皮爾遜相似度,'
    print recommend(mymat2,2,simMeas=pearsSim)
    print '奇異值分解推薦方法:'
    print '餘弦相似度,'
    print recommend(mymat2,2,estMethod=svdEst)
    print '歐式距離相似度,'
    print recommend(mymat2,2,simMeas=ecludSim,estMethod=svdEst)
    print '皮爾遜相似度,'
    print recommend(mymat2,2,simMeas=pearsSim,estMethod=svdEst)

#二值化列印資料
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 ''

# 利用SVD 對 手寫字型 資料進行壓縮
# 原始資料為 32*32 =1024
# 而利用奇異值分解 得到三個矩陣 利用2個奇異值就可以比較完整的 重構原來的矩陣
# 即奇異值分解壓縮後 所用資料為 32*2 + 32*2 + 2 = 130
# 将近十倍的壓縮率
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 "****原始矩陣******"
    printMat(myMat, thresh)#二值化列印資料
    print '大小:'
    print  shape(myMat)
    U,Sigma,VT = la.svd(myMat)# 奇異值分解
    SigRecon = mat(zeros((numSV, numSV)))# 簡化的奇異值對角矩陣
    for k in range(numSV):               
        SigRecon[k,k] = Sigma[k]          # 替換對角上的元素
    reconMat = U[:,:numSV]*SigRecon*VT[:numSV,:] 
    # 簡化後的 奇異值對角矩陣 以及截斷的 U, VT 逆變換得到重構後的矩陣
    print "****使用 %d 個奇異值重構後的矩陣******" % numSV
    printMat(reconMat, thresh)
    print '大小:'
print shape(reconMat)
           
PYTHON機器學習實戰——SVD奇異值分解 資料降維PYTHON機器學習實戰——SVD奇異值分解 資料降維