计算机视觉
图像处理

机器学习实战笔记——利用SVD简化数据

SVD(Singular Value Decomposition)奇异值分解,可以用来简化数据,去除噪声,提高算法的结果。

一、SVD与推荐系统

下图由餐馆的菜和品菜师对这些菜的意见组成,品菜师可以采用1到5之间的任意一个整数来对菜评级,如果品菜师没有尝过某道菜,则评级为0

建立一个新文件svdRec.py并加入如下代码:

  1. def loadExData():
  2.     return[[00022],
  3.            [00033],
  4.            [00011],
  5.            [11100],
  6.            [22200],
  7.            [55500],
  8.            [11100]]

 

  1. >>> import svdRec
  2. >>> Data=svdRec.loadExData()
  3. >>> Data
  4. [[00022], [00033], [00011], [11100], [22200], [55500], [11100]]
  5. >>> U,Sigma,VT=linalg.svd(Data)
  6. >>> Sigma
  7. array([  9.64365076e+00,   5.29150262e+00,   8.05799147e16,
  8.          2.43883353e16,   2.07518106e17])

我们可以发现得到的特征值,前两个比其他的值大很多,所以可以将最后三个值去掉,因为他们的影响很小。

可以看出上图中前三个人,喜欢烤牛肉和手撕猪肉,这些菜都是美式烧烤餐馆才有的菜,这两个特征值可以分别对应到美食BBQ和日式食品两类食品上,所以可以认为这三个人属于一类用户,下面四个人属于一类用户,这样推荐就很简单了。

建立一个新文件svdRec.py并加入如下代码:

  1. def loadExData():
  2.   return[[11100],
  3.     [22200],
  4.     [11100],
  5.     [55500],
  6.     [11022],
  7.     [00033],
  8.     [00011]]

SVD分解:

  1. >>> reload(svdRec)
  2. <module ‘svdRec’ from ‘svdRec.py’>
  3. >>> Data=svdRec.loadExData()
  4. >>> Data
  5. [[11100], [22200], [11100], [55500], [11022], [00033], [00011]]
  6. >>> U,Sigma,VT=linalg.svd(Data)
  7. >>> Sigma
  8. array([  9.72140007e+00,   5.29397912e+00,   6.84226362e01,
  9.          1.67441533e15,   3.39639411e16])

我们可以发现得到的特征值,前3个比其他的值大很多,所以可以将最后2个值去掉,因为他们的影响很小。

上面例子就可以将原始数据用如下结果近似:

二、基于协同过滤的推荐引擎

协同过滤(collaborative filtering)是通过将用户与其他用户的数据进行对比来实现推荐的。

1.相似度计算

  1. from numpy import *
  2. from numpy import linalg as la
  3. def eulidSim(inA,inB):
  4.     return 1.0/(1.0+la.norm(inA,inB))
  5. def pearsSim(inA,inB):
  6.     if len(inA<3):return 1.0
  7.     return 0.5+0.5*corrcoef(inA,inB,rowvar=0)[0][1]
  8. def cosSim(inA,inB):
  9.     num=float(inA.T*inB)
  10.     denom=la.norm(inA)*la.norm(inB)
  11.     return 0.5+0.5*(num/denom)

2.基于物品的相似度与基于用户的相似度

当用户数目很多时,采用基于物品的相似度计算方法更好。

3.示例:基于物品相似度的餐馆菜肴推荐引擎

  1. from numpy import *
  2. from numpy import linalg as la
  3. def loadExData():
  4.   return[[11100],
  5.     [22200],
  6.     [11100],
  7.     [55500],
  8.     [11022],
  9.     [00033],
  10.     [00011]]
  11. def loadExData2():
  12.     return[[00000400005],
  13.            [00030400003],
  14.            [00004001040],
  15.            [33400002200],
  16.            [54500005500],
  17.            [00005010050],
  18.            [43400005501],
  19.            [00040400004],
  20.            [00020250012],
  21.            [00005000040],
  22.            [10000001200]]
  23. def ecludSim(inA,inB):
  24.     return 1.0/(1.0 + la.norm(inA – inB))
  25. def pearsSim(inA,inB):
  26.     if len(inA) < 3 : return 1.0
  27.     return 0.5+0.5*corrcoef(inA, inB, rowvar = 0)[0][1]
  28. def cosSim(inA,inB):
  29.     num = float(inA.T*inB)
  30.     denom = la.norm(inA)*la.norm(inB)
  31.     return 0.5+0.5*(num/denom)
  32. #计算在给定相似度计算方法的条件下,用户对物品的估计评分值
  33. #standEst()函数中:参数dataMat表示数据矩阵,user表示用户编号,simMeas表示相似度计算方法,item表示物品编号
  34. def standEst(dataMat,user,simMeas,item):
  35.     n=shape(dataMat)[1#shape用于求矩阵的行列
  36.     simTotal=0.0; ratSimTotal=0.0
  37.     for j in range(n):
  38.         userRating=dataMat[user,j]
  39.         if userRating==0:continue #若某个物品评分值为0,表示用户未对物品评分,则跳过,继续遍历下一个物品
  40.         #寻找两个用户都评分的物品
  41.         overLap=nonzero(logical_and(dataMat[:,item].A>0,dataMat[:,j].A>0))[0]
  42.         if len(overLap)==0:similarity=0
  43.         else: similarity=simMeas(dataMat[overLap,item],dataMat[overLap,j])
  44.         #print’the %d and%d similarity is: %f’ %(item,j,similarity)
  45.         simTotal+=similarity
  46.         ratSimTotal+=similarity*userRating
  47.     if simTotal==0return 0
  48.     elsereturn ratSimTotal/simTotal
  49. def recommend(dataMat,user,N=3,simMeas=cosSim,estMethod=standEst):
  50.     #寻找未评级的物品
  51.     unratedItems=nonzero(dataMat[user,:].A==0)[1]
  52.     if len(unratedItems)==0return ‘you rated everything’
  53.     itemScores=[]
  54.     for item in unratedItems:
  55.         estimatedScore=estMethod(dataMat,user,simMeas,item) #对每一个未评分物品,调用standEst()来产生该物品的预测得分
  56.         itemScores.append((item,estimatedScore)) #该物品的编号和估计得分值放入一个元素列表itemScores中
  57.     #对itemScores进行从大到小排序,返回前N个未评分物品
  58.     return sorted(itemScores,key=lambda jj:jj[1],reverse=True)[:N]
  59. def svdEst(dataMat, user, simMeas, item):
  60.     n = shape(dataMat)[1]
  61.     simTotal = 0.0; ratSimTotal = 0.0
  62.     U,Sigma,VT = la.svd(dataMat)
  63.     Sig4 = mat(eye(4)*Sigma[:4]) #arrange Sig4 into a diagonal matrix
  64.     xformedItems = dataMat.T * U[:,:4] * Sig4.I  #create transformed items
  65.     for j in range(n):
  66.         userRating = dataMat[user,j]
  67.         if userRating == 0 or j==item: continue
  68.         similarity = simMeas(xformedItems[item,:].T,
  69.                              xformedItems[j,:].T)
  70.         print ‘the %d and %d similarity is: %f’ % (item, j, similarity)
  71.         simTotal += similarity
  72.         ratSimTotal += similarity * userRating
  73.     if simTotal == 0return 0
  74.     elsereturn ratSimTotal/simTotal

其中dataMat[:,item].A,表示找出item列,因为是matrix,用.A转成array,logical_and,其实就是找出最item列和j列都>0,只有都大于0才会是true,nonzero会给出其中不为0的index。

进行SVD分解:

  1. >>>from numpy import linalg as la
  2. >>> U,Sigma,VT=la.svd(mat(svdRec.loadExData2()))
  3. >>> Sigma
  4. array([ 1.38487021e+011.15944583e+011.10219767e+01,
  5.         5.31737732e+004.55477815e+002.69935136e+00,
  6.         1.53799905e+006.46087828e014.45444850e01,
  7.         9.86019201e029.96558169e17])

如何决定r?有个定量的方法是看多少个奇异值可以达到90%的能量,其实和PCA一样,由于奇异值其实是等于data×dataT特征值的平方根,所以总能量就是特征值的和

  1. >>> Sig2=Sigma**2
  2. >>> sum(Sig2)
  3. 541.99999999999932

而取到前4个时,发现总能量大于90%,因此r=4

  1. >>> sum(Sig2[:3])
  2. 500.50028912757909

SVD分解的关键在于,降低了user的维度,从n变到了4

  1. def svdEst(dataMat, user, simMeas, item):
  2.     n = shape(dataMat)[1]
  3.     simTotal = 0.0; ratSimTotal = 0.0
  4.     U,Sigma,VT = la.svd(dataMat)
  5.     Sig4 = mat(eye(4)*Sigma[:4]) #arrange Sig4 into a diagonal matrix
  6.     xformedItems = dataMat.T * U[:,:4] * Sig4.I  #create transformed items
  7.     for j in range(n):
  8.         userRating = dataMat[user,j]
  9.         if userRating == 0 or j==item: continue
  10.         similarity = simMeas(xformedItems[item,:].T,
  11.                              xformedItems[j,:].T)
  12.         print ‘the %d and %d similarity is: %f’ % (item, j, similarity)
  13.         simTotal += similarity
  14.         ratSimTotal += similarity * userRating
  15.     if simTotal == 0return 0
  16.     elsereturn ratSimTotal/simTotal

其中关键一步,dataMat.T * U[:,:4] * Sig4.I

将m×n的dataMat用特征值缩放转换为n×4的item和user类的矩阵

  1. >>> myMat=mat(svdRec.loadExData2())
  2. >>> myMat
  3. matrix([[00000400005],
  4.         [00030400003],
  5.         [00004001040],
  6.         [33400002200],
  7.         [54500005500],
  8.         [00005010050],
  9.         [43400005501],
  10.         [00040400004],
  11.         [00020250012],
  12.         [00005000040],
  13.         [10000001200]])
  14. >>> svdRec.recommend(myMat,1,estMethod=svdRec.svdEst)
  15. the 0 and 3 similarity is0.490950
  16. the 0 and 5 similarity is0.484274
  17. the 0 and 10 similarity is0.512755
  18. the 1 and 3 similarity is0.491294
  19. the 1 and 5 similarity is0.481516
  20. the 1 and 10 similarity is0.509709
  21. the 2 and 3 similarity is0.491573
  22. the 2 and 5 similarity is0.482346
  23. the 2 and 10 similarity is0.510584
  24. the 4 and 3 similarity is0.450495
  25. the 4 and 5 similarity is0.506795
  26. the 4 and 10 similarity is0.512896
  27. the 6 and 3 similarity is0.743699
  28. the 6 and 5 similarity is0.468366
  29. the 6 and 10 similarity is0.439465
  30. the 7 and 3 similarity is0.482175
  31. the 7 and 5 similarity is0.494716
  32. the 7 and 10 similarity is0.524970
  33. the 8 and 3 similarity is0.491307
  34. the 8 and 5 similarity is0.491228
  35. the 8 and 10 similarity is0.520290
  36. the 9 and 3 similarity is0.522379
  37. the 9 and 5 similarity is0.496130
  38. the 9 and 10 similarity is0.493617
  39. [(43.3447149384692283), (73.3294020724526967), (93.328100876390069)]

转载注明来源:CV视觉网 » 机器学习实战笔记——利用SVD简化数据

分享到:更多 ()
扫描二维码,给作者 打赏
pay_weixinpay_weixin

请选择你看完该文章的感受:

2不错 0超赞 0无聊 0扯淡 0不解 0路过

评论 6

评论前必须登录!