您的位置:首页 > 其它

[机器学习]-SVD奇异值分解的基本原理和运用

2016-12-22 19:45 274 查看
SVD奇异值分解:

   SVD是一种可靠的正交矩阵分解法。可以把A矩阵分解成U,∑,VT三个矩阵相乘的形式。(Svd(A)=[U*∑*VT],A不必是方阵,U,VT必定是正交阵,S是对角阵<以奇异值为对角线,其他全为0>)

用途

     信息检索(LSA:隐性语义索引,LSA:隐性语义分析),分解后的奇异值代表了文章的主题或者概念,信息检索的时候同义词,或者说同一主题下的词会映射为同一主题,这样就可以提高搜索效率

     数据压缩:通过奇异值分解,选择能量较大的前N个奇异值来代替所有的数据信息,这样可以降低噪声,节省空间。

推荐系统:主要是降噪,矩阵变换至低维空间,方便计算(目前没有意识到它对推荐精确度的提升有什么具体作用)。

原理:矩阵分解,矩阵变换,数据降维

基于协同过滤的推荐系统(相关知识):

  相似度计算:A(a1,a2,a3),B(b1,b2,b3)

1.欧氏距离相似度:点到点的距离在多维空间的推广 ,||A-B||表示A-B的2范数。

  

# -*- coding:utf-8 -*-
# Filename: svd.py
# Author:Ljcx

from numpy import*

class Svd(object):

def loadExData(self):
data = [[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]]
return data

def loadExData2(self):
"""
列表示商品,行表示用户的评分
"""
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]]

# 相似度计算:inA,inB为列向量还是行向量,基于我们需要计算相似的维度
def ecludSim(self, inA, inB):
"""norm()求范数
范数表示数值平方开方,inA-inB的范数 = inA和inB的欧氏距离
"""
return 1.0 / (1.0 + linalg.norm(inA - inB))

def pearsSim(self, inA, inB):
"""corrcoef()求皮尔逊相关系数 [-1,1]
皮尔逊相关系数:0.5+0.5*corrcoef()规范化到[0,1]
"""
if len(inA) < 3:
return 1.0
return 0.5 + 0.5 * corrcoef(inA, inB, rowvar=0)[0][1]

def cosSim(self, inA, inB):
"""
余玄相似度:即两个向量的余玄夹角值[-1,1]
"""
num = float(inA.T * inB)
denom = linalg.norm(inA) * linalg.norm(inB)
return 0.5 + 0.5 * (num / denom)

# 奇异值分解==》矩阵重构:可用于图像压缩
def svdMt(self, data):
"""
奇异值分解矩阵data = U * Sigma *VT (用分解后的矩阵可以近似地表示原矩阵
节省空间,
Sigma是个奇异值方阵)
"""
U, Sigma, VT = linalg.svd(data)
""" 前两个奇异值已经几乎包含了所有的信息远大于后三个数据,所以忽略掉后三个
数据
启发式搜索:选择奇异之平方和大于总平方和90%为标准
"""
num = 0  # 需要保存的奇异值个数
for i in range(len(Sigma)):
if (linalg.norm(Sigma[:i + 1]) / linalg.norm(Sigma)) > 0.9:
num = i + 1
break
# 构建对角矩阵
sig3 = mat(eye(num) * Sigma[:num])
"""选取前num个奇异值重构数据集
"""
newData = U[:, :num] * mat(sig3) * VT[:num, :]
print newData
print newData.astype(int)
return U, Sigma, VT, num, newData

"""
基于相似度的推荐引擎:
只需要对用户所购商品和其他商品做相似度计算,选取TOPn个作为推荐
基于SVD的推荐引擎:
先进行奇异值分解,选取前n个奇异值(能量之和大于90%,奇异之平方和大于总平方和
90%为标准),作为需要降维的维数,原数据往低维空间投影。Data.T*U[:,:n]*Sigma[:,:4]
寻找指定一个商品的所有评分x[,,,]和每一个商品的所有评分做相似度计算,相似度求和
"""

# 相似度推荐
def standEst(self):
pass

def svdEst(self, dataMat, xformedItems, user, simMeas, item):
"""计算相似度并计算评分
# dataMat:原始数据
# user:用户编号
# simMeas:相似度计算方法
# item:商品编号
# xformedItems:降维后的数据
"""
n = shape(dataMat)[1]  # 获取列,多少个商品
simTotal = 0.0
ratSimTotal = 0.0
# 计算指定用户评价过的商品与其他所有用户的评价过的商品做相似度计算,来估计
# 指定的未评价商品item的评分
for j in range(n):
userRating = dataMat[user, j]
if userRating == 0 or j == item:
continue
similarity = simMeas(xformedItems[item, :].T, xformedItems[j, :].T)
print 'the %d and %d similarity is: %f' % (item, j, similarity)
simTotal += similarity  # 相似度求和
ratSimTotal += similarity * userRating  # 相似度乘以评分在求和
if simTotal == 0:
return 0
else:
return ratSimTotal / simTotal  # 根据相似度对一个指定商品给一个评分

def recommend(self, dataMat, user, N=3, simMeas=cosSim, estMethod=svdEst):
"""
# 根据SVD空间评分推荐:寻找所有该用户未评分的商品,对每个商品进行评分估计()
"""
unratedItems = nonzero(dataMat[user, :].A == 0)[1]  # findunrated items
if len(unratedItems) == 0:
return 'you rated everything'
U, Sigma, VT, num, newData = self.svdMt(dataMat)
sig = mat(eye(num) * Sigma[:num])  # 构建对角矩阵
xformedItems = dataMat.T * U[:, :num] * sig.I  # 数据投影降维
print "----xform---"
print xformedItems
itemScores = []
for item in unratedItems:
estimatedScore = estMethod(
dataMat, xformedItems, user, simMeas, item)  # 评分
itemScores.append((item, estimatedScore))
return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[:N]

def loadImageData(self):
"""
加载图像数据
"""
fp = open("image.txt", "r")
imageData = []
for line in fp.readlines():
lineData = []
for i in range(len(line) - 1):
lineData.append(int(line[i]))
imageData.append(lineData)
return mat(imageData)

def imageCompress(self):
"""svd图像压缩 == 分解矩阵之后 选择几个重要的奇异值对U ,Sigma ,VT 进行切割,
切割后的矩阵的乘积仍可以表示原矩阵,我们只需存储这三个矩阵就可以在使用的时候
还原原矩阵了
"""
data = self.loadImageData()
self.printMat(data, 0.8)  # 压缩前数据
print"---------------------------------------------------------"
U, Sigma, VT, num, newData = self.svdMt(data)
self.printMat(newData, 0.8)  # 压缩后还原的数据
print Sigma
print "num:" + str(num)
print '前 %d 个奇异值的平方和达到了所有奇异值平方和的0.9以上则2个奇异值重构矩阵可表示原矩阵:' % (num)
U = U[:, :num]
Sigma = Sigma[:num]
VT = VT[:num, :]
print "U:" + str(shape(U))
print U
print "Sigma:" + str(shape(Sigma))
print Sigma
print "VT:" + str(shape(VT))
print VT
print "压缩前存储空间:", str(shape(data)[0] * shape(data)[1])
print "压缩后存储空间:", str(shape(U)[0] * shape(U)[1]
+ shape(Sigma)[0] * shape(Sigma)[0]
+ shape(VT)[0] * shape(VT)[1])

def printMat(self, 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 ''

if __name__ == "__main__":
sd = Svd()
data = sd.loadExData2()
sd.recommend(mat(data), 2, 3, sd.cosSim, sd.svdEst)
sd.imageCompress()


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: