优点:简化数据,去除噪声,提高算法的结果
缺点:数据的转换可能难以理解
适用数据类型:数值型数据
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%的能量,就可以得到重要的特征并去掉噪声。