SVD简化数据(《Machine Learning in Action》笔记)

优点:简化数据,去除噪声,提高算法的结果
缺点:数据的转换可能难以理解
适用数据类型:数值型数据

LSI(Latent Semantic Indexing),浅层语义索引
LSA(Latent Semantic Analysis),浅层语义分析

import numpy

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]]
Data = loadExData()
U, sigma, VT = numpy.linalg.svd(Data)
print sigma     #sigma矩阵除了对角线元素其他均为0,所以仅返回对角元素能够节省空间
sig2 = numpy.mat([[sigma[0], 0], [0, sigma[1]]])        #通过三个矩阵对原始矩阵进行近似
dataMat = U[:, :2] * sig2 * VT[:2, :]
print dataMat

协同过滤:不关心物品的描述属性,而是严格按照许多用户的观点来计算相似度。

''' 三个相似度函数 inA, inB都是列向量 '''
def ecludSim(inA, inB):
    return 1.0 /(1.0 + numpy.linalg.norm(inA - inB))        #norm函数计算欧氏距离;距离为0时,相似度为1

def pearsSim(inA, inB):
    if len(inA) < 3:
        return 1.0
    return 0.5 + 0.5 * numpy.corrcoef(inA, inB, rowvar = 0)[0][1]

def cosSim(inA, inB):
    num = float(inA.T * inB)
    denom = numpy.linalg.norm(inA) * numpy.linalg.norm(inB)
    return 0.5 + 0.5 * (num / denom)

''' 这里采用列向量的表示方法,即 基于物品相似度方法 到底是基于物品还是基于用户,主要取决于物品以及用户的数量 对于大部分产品导向的推荐引擎而言, 用户的数量往往大于物品的数量。 所以 这里采用 基于用户的相似度 '''
print ecludSim(numpy.mat(Data)[:, 0], numpy.mat(Data)[:, 0])
print cosSim(numpy.mat(Data)[:, 0], numpy.mat(Data)[:, 0])
print pearsSim(numpy.mat(Data)[:, 0], numpy.mat(Data)[:, 0])

def standEst(dataMat, user, simMeas, item):
    ''' 给定相似度计算方法的条件下,用户对物品的估计评分值 输入:数据矩阵, 用户编号,相似度计算方法,物品编号 '''
    n = numpy.shape(dataMat)[1]     #物品数目
    simTotal = 0.0
    ratSimTotal = 0.0
    for j in range(n):      #遍历每个物品
        userRating = dataMat[user, j]
        if userRating == 0:
            continue        #如果用户没有对该物品进行打分,则跳过该物品
        overLap = numpy.nonzero(logical_and(dataMat[:, item].A > 0, dataMat[:, j].A > 0))[0]
        if len(overLap) == 0:       #两个物品当中没有重合的元素,相似度为0
            similarity = 0
        else:
            similarity = simMeas(dataMat[overLap, item], dataMat[overLap, j])       #计算重合物品的相似度
        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 = numpy.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]       #从大到小逆序排列,第一个值是最大值

使用SVD来改进推荐系统

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]]

U,sigma, VT = numpy.linalg.svd(numpy.mat(loadExData2()))
print sigma
Sig2 = sigma**2
print sum(Sig2) * 0.9       #总能量的90%:487.8
print sum(Sig2[:3])     #前三维:500.5, 超过了总能量的90%, 所以将11维数据映射到三维

def svdEst(dataMat, user, simMeas, item):
    ''' 基于SVD的评分估计 '''
    n = numpy.shape(dataMat)[1]
    simTotal = 0.0
    ratSimTotal = 0.0
    U, sigma, VT = numpy.linalg.svd(dataMat)
    Sig4 = numpy.mat(numpy.eye(4) * sigma[:4])      #只利用了包含90%能量值的奇异值,构建对角矩阵
    xformedItems = dataMat.T * U[:, :4] * Sig4.I        #利用U矩阵将物品矩阵转换到低位空间中
    for j in range(n):
        userRating = dataMat[user, j]
        if userRating == 0 or j == item:
            continue
        similarity = simMeas(xformedItems[item,:].T,xformedItems[j,:].T)
        simTotal += similarity
        ratSimTotal += similarity * userRating
    if simTotal == 0:
        return 0
    else:
        return ratSimTotal / simTotal

用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 = numpy.mat(myl)
    print '******original matrxi******'
    printMat(myMat, thresh)     #矩阵调入后输出该矩阵
    U, sigma, VT = numpy.linalg.svd(myMat)
    SigRecon = numpy.mat(numpy.zeros((numSV, numSV)))       #建立一个全0矩阵
    for k in range(numSV):      #在对角线上添加奇异值
        SigRecon[k, k] = sigma[k]
    reconMat = U[:, :numSV] * SigRecon * VT[:numSV, :]      #得到重构后的矩阵
    print '****reconstructed matrxi using %d singular values ********' %numSV
    printMat(reconMat, thresh)

imgCompress()

SVD是一种强大的降维工具,可以利用它来逼近矩阵并从中提取重要特征。通过保留矩阵80%—90%的能量,就可以得到重要的特征并去掉噪声。

你可能感兴趣的:(机器学习)