• PCA和SVD数据降维


    PCA(Principal Component Analysis) 是一种常见的数据分析方式,常用于高维数据的降维,可用于提取数据的主要特征分量。

    最大可分性

    基向量乘原始矩阵会将矩阵映射到这个基向量空间中,如果基的数量少于向量本身的维数,则可以达到降维的效果。

    如何选取基?

    希望投影后的投影值尽可能分散,因为如果重叠就会有样本消失。当然这个也可以从熵的角度进行理解,熵越大所含信息越多。

    数据的分散程度可以用方差来表示,所以需要将方差最大化

    一维是方差,而对于高维数据,我们用协方差进行约束,协方差可以表示两个变量的相关性。为了让两个变量尽可能表示更多的原始信息,我们希望它们之间不存在线性相关性。

    协方差公式:Cov(a,b)=\frac{1}{m-1}\sum_{i=1}^{m}(a_{i}-\mu _{a})(b_{i}-\mu _{b})))

    为了方便处理,我们将每个变量的均值都化为 0

    Cov(a,b)=\frac{1}{m}\sum_{i=1}^{m}a_{i}b_{i}

    当样本数较大时,不必在意其是 m 还是 m-1,为了方便计算,我们分母取 m。

    当协方差为0时,表示两个变量线性不相关,为了让协方差为0,我们选择第二个基时只能在与第一个基正交的方向上进行选择,因此最终选择的两个方向一定是正交的。

    至此,我们得到了降维问题的优化目标:将一组 N 维向量降为 K 维,其目标是选择 K 个单位正交基,使得原始数据变换到这组基上后,各变量两两间协方差为 0,而变量方差则尽可能大(在正交的约束下,取最大的 K 个方差)

    \frac{1}{m}XX^{T}=\begin{pmatrix} \frac{1}{m}\sum_{i=1}^{m}a_{i}^{2} &\frac{1}{m}\sum_{i=1}^{m}a_{i}b_{i} \\ \frac{1}{m}\sum_{i=1}^{m}a_{i}b_{i} & \frac{1}{m}\sum_{i=1}^{m}b_{i}^{2} \end{pmatrix}=\begin{pmatrix} Cov(a,a) & Cov(a,b)\\ Cov(b,a) & Cov(b,b) \end{pmatrix}

    根据我们的优化条件,我们需要将除对角线外的其它元素化为 0,并且在对角线上将元素按大小从上到下排列(变量方差尽可能大)

    设原始数据矩阵 X 对应的协方差矩阵为 C,而 P 是一组基按行组成的矩阵,设 Y=PX,则 Y 为 X 对 P 做基变换后的数据。设 Y 的协方差矩阵为 D,我们推导一下 D 与 C 的关系:

    D=\frac{1}{m}YY^{T}=\frac{1}{m}(PX)(PX)^{T}=\frac{1}{m}PXX^{T}P^{T}=P(\frac{1}{m}XX^{T})P^{T}=PCP^{T}

    所以P为所要求的基矩阵

    求解步骤

    总结一下 PCA 的算法步骤:

    设有 m 条 n 维数据。

    1. 将原始数据按列组成 n 行 m 列矩阵 X;
    2. 将 X 的每一行进行零均值化,即减去这一行的均值;
    3. 求出协方差矩阵 C=\frac{1}{m}XX^{T}
    4. 求出协方差矩阵的特征值及对应的特征向量;
    5. 将特征向量按对应特征值大小从上到下按行排列成矩阵,取前 k 行组成矩阵 P;
    6. Y=PX即为降维到 k 维后的数据

    PCA与SVD本质一样

    SVD:

    SVD的基矩阵是A^{T}AAA^{T}的特征值分解的特征向量按列组成的正交矩阵左奇异矩阵V,右奇异矩阵U,PCA只与SVD的右奇异向量的压缩效果相同

    为什么分左奇异右奇异矩阵?

    因为SVD所求的矩阵不是方阵,协方差矩阵不一样

    当矩阵为方阵是SVD等价于PCA

    A=\frac{X^{T}}{\sqrt{m}},则A^{T}A=(\frac{X^{T}}{\sqrt{m}})^{T}\frac{X^{T}}{\sqrt{m}}=\frac{1}{m}XX^{T}

    SVD与PCA等价,所以PCA问题可以转化为SVD问题求解,那转化为SVD问题有什么好处?

    有三点:

    1. 一般 X 的维度很高,A^{T}A 的计算量很大
    2. 方阵的特征值分解计算效率不高
    3. SVD除了特征值分解这种求解方式外,还有更高效且更准确的迭代求解法,避免了A^{T}A 的计算

    其实,PCA只与SVD的右奇异向量的压缩效果相同。

    1. 如果取V的前 k 行作为变换矩阵 P_{k\times n} ,则 Y_{k\times m}=P_{k\times n}X_{n\times m} ,起到压缩行即降维的效果
    2. 如果取 U的前 k行作为变换矩阵 P_{d\times m} ,则  Y_{n\times d}=X_{n\times m}P_{m\times d},起到压缩列即去除冗余样本的效果。

    1. from __future__ import print_function
    2. from numpy import *
    3. import matplotlib.pyplot as plt
    4. print(__doc__)
    5. def loadDataSet(fileName,delim='\t'):
    6. fr=open(fileName)
    7. stringArr=[line.strip().split(delim) for line in fr.readlines()]
    8. datArr=[map(float,line) for line in stringArr]
    9. return mat(datArr)
    10. def pca(dataMat,topNfeat=9999999):
    11. """pca
    12. Args:
    13. dataMat 原数据集矩阵
    14. topNfeat 应用的N个特征
    15. Returns:
    16. lowDDataMat 降维后数据集
    17. reconMat 新的数据集空间
    18. """
    19. # 计算每一列的均值
    20. meanVals=mean(dataMat,axis=0)
    21. # print 'meanVals', meanVals
    22. # 每个向量同时都减去 均值
    23. meanRemoved=dataMat-meanVals
    24. # print 'meanRemoved=', meanRemoved
    25. # cov协方差=[(x1-x均值)*(y1-y均值)+(x2-x均值)*(y2-y均值)+...+(xn-x均值)*(yn-y均值)+]/(n-1)
    26. '''
    27. 方差: (一维)度量两个随机变量关系的统计量
    28. 协方差: (二维)度量各个维度偏离其均值的程度
    29. 协方差矩阵: (多维)度量各个维度偏离其均值的程度
    30. 当 cov(X, Y)>0时,表明X与Y正相关;(X越大,Y也越大;X越小Y,也越小。这种情况,我们称为“正相关”。)
    31. 当 cov(X, Y)<0时,表明X与Y负相关;
    32. 当 cov(X, Y)=0时,表明X与Y不相关。
    33. '''
    34. covMat=cov(meanRemoved,rowvar=0)
    35. # eigVals为特征值, eigVects为特征向量
    36. eigVals,eigVects=linalg.eig(mat(covMat))
    37. # print 'eigVals=', eigVals
    38. # print 'eigVects=', eigVects
    39. # 对特征值,进行从小到大的排序,返回从小到大的index序号
    40. # 特征值的逆序就可以得到topNfeat个最大的特征向量
    41. '''
    42. >>> x = np.array([3, 1, 2])
    43. >>> np.argsort(x)
    44. array([1, 2, 0]) # index,1 = 1; index,2 = 2; index,0 = 3
    45. >>> y = np.argsort(x)
    46. >>> y[::-1]
    47. array([0, 2, 1])
    48. >>> y[:-3:-1]
    49. array([0, 2]) # 取出 -1, -2
    50. >>> y[:-6:-1]
    51. array([0, 2, 1])
    52. '''
    53. eigValInd=argsort(eigVals)
    54. # print 'eigValInd1=', eigValInd
    55. # -1表示倒序,返回topN的特征值[-1 到 -(topNfeat+1) 但是不包括-(topNfeat+1)本身的倒叙]
    56. eigValInd=eigValInd[:-(topNfeat+1):-1]
    57. # print 'eigValInd2=', eigValInd
    58. # 重组 eigVects 最大到最小
    59. redEigVects=eigVects[:,eigValInd]
    60. # print 'redEigVects=', redEigVects.T
    61. # 将数据转换到新空间
    62. # print "---", shape(meanRemoved), shape(redEigVects)
    63. lowDDataMat=meanRemoved*redEigVects
    64. reconMat=(lowDDataMat*redEigVects.T)+meanVals
    65. # print 'lowDDataMat=', lowDDataMat
    66. # print 'reconMat=', reconMat
    67. return lowDDataMat,reconMat
    68. def replaceNanWithMean():
    69. datMat=loadDataSet('data/13.PCA/secom.data', ' ')
    70. numFeat=shape(datMat)[1]
    71. for i in range(numFeat):
    72. # 对value不为NaN的求均值
    73. # .A 返回矩阵基于的数组
    74. meanVal=mean(datMat[nonzero(~isnan(datMat[:,i].A))[0],i])
    75. # 将value为NaN的值赋值为均值
    76. datMat[nonzero(isnan(datMat[:,i].A))[0],i]=meanVal
    77. return datMat
    78. def show_picture(dataMat,reconMat):
    79. fig=plt.figure()
    80. ax=fig.add_subplot(111)
    81. ax.scatter(dataMat[:,0].flatten().A[0],dataMat[:,1].flatten().A[0],marker='^',s=90,c='green')
    82. ax.scatter(reconMat[:, 0].flatten().A[0], reconMat[:, 1].flatten().A[0], marker='v', s=50, c='red')
    83. plt.show()
    84. def analyse_data(dataMat):
    85. meanVals=mean(dataMat,axis=0)
    86. meanRemoved=dataMat-meanVals
    87. covMat=cov(meanRemoved,rowvar=0)
    88. eigvals,eigVects=linalg.eig(mat(covMat))
    89. eigValInd=argsort(eigvals)
    90. topNfeat=20
    91. eigValInd=eigValInd[:-(topNfeat+1):-1]
    92. cov_all_score=float(sum(eigvals))
    93. sum_cov_score=0
    94. for i in range(0,len(eigValInd)):
    95. line_cov_score=float(eigvals[eigValInd[i]])
    96. sum_cov_score+=line_cov_score
    97. '''
    98. 我们发现其中有超过20%的特征值都是0。
    99. 这就意味着这些特征都是其他特征的副本,也就是说,它们可以通过其他特征来表示,而本身并没有提供额外的信息。
    100. 最前面15个值的数量级大于10^5,实际上那以后的值都变得非常小。
    101. 这就相当于告诉我们只有部分重要特征,重要特征的数目也很快就会下降。
    102. 最后,我们可能会注意到有一些小的负值,他们主要源自数值误差应该四舍五入成0.
    103. '''
    104. print('主成分: %s, 方差占比: %s%%, 累积方差占比: %s%%' % (format(i+1, '2.0f'), format(line_cov_score/cov_all_score*100, '4.2f'), format(sum_cov_score/cov_all_score*100, '4.1f')))
    1. import numpy as np
    2. x=np.array([3,1,2])
    3. print(np.argsort(x))
    4. y = np.argsort(x)
    5. print(y)
    6. print(y[::-1])
    7. print(y[1:3:1])
    1. # 加载数据,并转化数据类型为float
    2. dataMat=loadDataSet('data/13.PCA/testSet.txt')
    3. # 只需要1个特征向量
    4. lowDmat,reconMat=pca(dataMat,1)
    5. # 只需要2个特征向量,和原始数据一致,没任何变化
    6. lowDmat,reconMat=pca(dataMat,2)
    7. print(shape(lowDmat))
    8. show_picture(dataMat,reconMat)
    9. show_picture(dataMat,lowDmat)
    10. show_picture(reconMat,lowDmat)
    1. # 利用PCA对半导体制造数据降维
    2. dataMat = replaceNanWithMean()
    3. print(shape(dataMat))
    4. # 分析数据
    5. analyse_data(dataMat)
    6. lowDmat, reconMat = pca(dataMat, 20)
    7. print (shape(lowDmat))
    8. show_picture(dataMat,reconMat)
    9. show_picture(dataMat,lowDmat)
    10. show_picture(reconMat,lowDmat)

    SVD:

    应用场景:

    1.信息检索-隐性语义检索(Latent Semantic Indexing, LSI)或 隐形语义分析(Latent Semantic Analysis, LSA)

    2.推荐系统

    1. 利用 SVD 从数据中构建一个主题空间。
    2. 再在该空间下计算其相似度。(从高维-低维空间的转化,在低维空间来计算相似度,SVD 提升了推荐系统的效率。

    3.图像压缩

    将图像矩阵进行奇异值分解,然后存储

    例如: 32*32=1024 => 32*2+2*1+32*2=130(2*1表示去掉了除对角线的0), 几乎获得了10倍的压缩比。

    推荐系统:

    基于物品的相似度和基于用户的相似度: 物品比较少则选择物品相似度,用户比较少则选择用户相似度。

    • 基于物品的相似度: 计算物品之间的距离。【耗时会随物品数量的增加而增加】
    • 由于物品A和物品C 相似度(相关度)很高,所以给买A的人推荐C。
    • 基于用户的相似度: 计算用户之间的距离。【耗时会随用户数量的增加而增加】
    • 由于用户A和用户C 相似度(相关度)很高,所以A和C是兴趣相投的人,对于C买的物品就会推荐给A。

    相似度计算:

    • inA, inB 对应的是 列向量
    1. 欧氏距离: 指在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。二维或三维中的欧氏距离就是两点之间的实际距离。
      • 相似度= 1/(1+欧式距离)
      • 相似度= 1.0/(1.0 + la.norm(inA - inB))
      • 物品对越相似,它们的相似度值就越大。
    2. 皮尔逊相关系数: 度量的是两个向量之间的相似度。
      • 相似度= 0.5 + 0.5*corrcoef() 【皮尔逊相关系数的取值范围从 -1 到 +1,通过函数0.5 + 0.5*corrcoef()这个函数计算,把值归一化到0到1之间】
      • 相似度= 0.5 + 0.5 * corrcoef(inA, inB, rowvar = 0)[0][1]
      • 相对欧氏距离的优势: 它对用户评级的量级并不敏感。
    3. 余弦相似度: 计算的是两个向量夹角的余弦值。
      • 余弦值 = (A·B)/(||A||·||B||) 【余弦值的取值范围也在-1到+1之间】
      • 相似度= 0.5 + 0.5*余弦值
      • 相似度= 0.5 + 0.5*( float(inA.T*inB) / la.norm(inA)*la.norm(inB))
      • 如果夹角为90度,则相似度为0;如果两个向量的方向相同,则相似度为1.0。

    推荐系统的原理

    • 推荐系统的工作过程: 给定一个用户,系统会为此用户返回N个最好的推荐菜。
    • 实现流程大致如下:
      1. 寻找用户没有评级的菜肴,即在用户-物品矩阵中的0值。
      2. 在用户没有评级的所有物品中,对每个物品预计一个可能的评级分数。这就是说: 我们认为用户可能会对物品的打分(这就是相似度计算的初衷)。
      3. 对这些物品的评分从高到低进行排序,返回前N个物品。
    1. #SVD
    2. from __future__ import print_function
    3. from numpy import linalg as la
    4. from numpy import *
    5. def loadExData3():
    6. # 利用SVD提高推荐效果,菜肴矩阵
    7. return[[2, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0],
    8. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5],
    9. [0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 0],
    10. [3, 3, 4, 0, 3, 0, 0, 2, 2, 0, 0],
    11. [5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0],
    12. [0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0],
    13. [4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5],
    14. [0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4],
    15. [0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0],
    16. [0, 0, 0, 3, 0, 0, 0, 0, 4, 5, 0],
    17. [1, 1, 2, 1, 1, 2, 1, 0, 4, 5, 0]]
    18. def loadExData2():
    19. # 书上代码给的示例矩阵
    20. return[[0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 5],
    21. [0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 3],
    22. [0, 0, 0, 0, 4, 0, 0, 1, 0, 4, 0],
    23. [3, 3, 4, 0, 0, 0, 0, 2, 2, 0, 0],
    24. [5, 4, 5, 0, 0, 0, 0, 5, 5, 0, 0],
    25. [0, 0, 0, 0, 5, 0, 1, 0, 0, 5, 0],
    26. [4, 3, 4, 0, 0, 0, 0, 5, 5, 0, 1],
    27. [0, 0, 0, 4, 0, 4, 0, 0, 0, 0, 4],
    28. [0, 0, 0, 2, 0, 2, 5, 0, 0, 1, 2],
    29. [0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0],
    30. [1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0]]
    31. def loadExData():
    32. """
    33. # 推荐引擎示例矩阵
    34. return[[4, 4, 0, 2, 2],
    35. [4, 0, 0, 3, 3],
    36. [4, 0, 0, 1, 1],
    37. [1, 1, 1, 2, 0],
    38. [2, 2, 2, 0, 0],
    39. [1, 1, 1, 0, 0],
    40. [5, 5, 5, 0, 0]]
    41. """
    42. # # 原矩阵
    43. # return[[1, 1, 1, 0, 0],
    44. # [2, 2, 2, 0, 0],
    45. # [1, 1, 1, 0, 0],
    46. # [5, 5, 5, 0, 0],
    47. # [1, 1, 0, 2, 2],
    48. # [0, 0, 0, 3, 3],
    49. # [0, 0, 0, 1, 1]]
    50. # 原矩阵
    51. return[[0, -1.6, 0.6],
    52. [0, 1.2, 0.8],
    53. [0, 0, 0],
    54. [0, 0, 0]]
    55. # 相似度计算,假定inA和inB 都是列向量
    56. # 基于欧氏距离
    57. def ecludSim(inA,inB):
    58. return 1.0/(1.0+la.norm(inA-inB))
    59. # pearsSim()函数会检查是否存在3个或更多的点。
    60. # corrcoef直接计算皮尔逊相关系数,范围[-1, 1],归一化后[0, 1]
    61. def pearsSim(inA,inB):
    62. # 如果不存在,该函数返回1.0,此时两个向量完全相关。
    63. if len(inA)<3:
    64. return 1.0
    65. return 0.5+0.5*corrcoef(inA,inB,rowvar=0)[0][1]
    66. # 计算余弦相似度,如果夹角为90度,相似度为0;如果两个向量的方向相同,相似度为1.0
    67. def cosSim(inA,inB):
    68. num=float(inA.T*inB)
    69. denom=la.norm(inA)*la.norm(inB)
    70. return 0.5+0.5*(num/denom)
    71. # 基于物品相似度的推荐引擎
    72. def standEst(dataMat,user,simMeas,item):
    73. """standEst(计算某用户未评分物品中,以对该物品和其他物品评分的用户的物品相似度,然后进行综合评分)
    74. Args:
    75. dataMat 训练数据集
    76. user 用户编号
    77. simMeas 相似度计算方法
    78. item 未评分的物品编号
    79. Returns:
    80. ratSimTotal/simTotal 评分(0~5之间的值)
    81. """
    82. # 得到数据集中的物品数目
    83. n=shape(dataMat)[1]
    84. # 初始化两个评分值
    85. simTotal=0.0
    86. ratSimTotal=0.0
    87. # 遍历行中的每个物品(对用户评过分的物品进行遍历,并将它与其他物品进行比较)
    88. for j in range(n):
    89. userRating=dataMat[user,j]
    90. # 如果某个物品的评分值为0,则跳过这个物品
    91. if userRating==0:
    92. continue
    93. # 寻找两个用户都评级的物品
    94. # 变量 overLap 给出的是两个物品当中已经被评分的那个元素的索引ID
    95. # logical_and 计算x1和x2元素的真值。
    96. overLap=nonzero(logical_and(dataMat[:,item].A>0,dataMat[:,j].A>0))[0]
    97. # 如果相似度为0,则两着没有任何重合元素,终止本次循环
    98. if len(overLap)==0:
    99. similarity=0
    100. # 如果存在重合的物品,则基于这些重合物重新计算相似度。
    101. else:
    102. similarity=simMeas(dataMat[overLap,item],dataMat[overLap,j])
    103. # print 'the %d and %d similarity is : %f'(iten,j,similarity)
    104. # 相似度会不断累加,每次计算时还考虑相似度和当前用户评分的乘积
    105. # similarity 用户相似度, userRating 用户评分
    106. simTotal+=similarity
    107. ratSimTotal+=similarity*userRating
    108. if simTotal==0:
    109. return 0
    110. # 通过除以所有的评分总和,对上述相似度评分的乘积进行归一化,使得最后评分在0~5之间,这些评分用来对预测值进行排序
    111. else:
    112. return ratSimTotal/simTotal
    113. # 基于SVD的评分估计
    114. # 在recommend() 中,这个函数用于替换对standEst()的调用,该函数对给定用户给定物品构建了一个评分估计值
    115. def svdEst(dataMat,user,simMeas,item):
    116. """svdEst( )
    117. Args:
    118. dataMat 训练数据集
    119. user 用户编号
    120. simMeas 相似度计算方法
    121. item 未评分的物品编号
    122. Returns:
    123. ratSimTotal/simTotal 评分(0~5之间的值)
    124. """
    125. # 物品数目
    126. n=shape(dataMat)[1]
    127. # 对数据集进行SVD分解
    128. simTotal=0.0
    129. ratSimTotal=0.0
    130. # 奇异值分解
    131. # 在SVD分解之后,我们只利用包含了90%能量值的奇异值,这些奇异值会以NumPy数组的形式得以保存
    132. U,Sigma,VT=la.svd(dataMat)
    133. # # 分析 Sigma 的长度取值
    134. # analyse_data(Sigma, 20)
    135. # 如果要进行矩阵运算,就必须要用这些奇异值构建出一个对角矩阵
    136. Sig4=mat(eye(4)*Sigma[:4])
    137. # 利用U矩阵将物品转换到低维空间中,构建转换后的物品(物品+4个主要的特征)
    138. xformedItems = dataMat.T * U[:, :4] * Sig4.I
    139. xformedItems1 = U[:, :4].T *dataMat
    140. print('dataMat', shape(dataMat))
    141. print('U[:, :4]', shape(U[:, :4]))
    142. print('Sig4.I', shape(Sig4.I))
    143. print('VT[:4, :]', (VT[:4, :]))
    144. print('xformedItems', (xformedItems))
    145. print('xformedItems1', (xformedItems1))
    146. # 对于给定的用户,for循环在用户对应行的元素上进行遍历
    147. # 这和standEst()函数中的for循环的目的一样,只不过这里的相似度计算时在低维空间下进行的。
    148. for j in range(n):
    149. userRating = dataMat[user, j]
    150. if userRating == 0 or j == item:
    151. continue
    152. # 相似度的计算方法也会作为一个参数传递给该函数
    153. similarity = simMeas(xformedItems[item, :].T, xformedItems[j, :].T)
    154. # for 循环中加入了一条print语句,以便了解相似度计算的进展情况。如果觉得累赘,可以去掉
    155. print('the %d and %d similarity is: %f' % (item, j, similarity))
    156. # 对相似度不断累加求和
    157. simTotal += similarity
    158. # 对相似度及对应评分值的乘积求和
    159. ratSimTotal += similarity * userRating
    160. if simTotal == 0:
    161. return 0
    162. else:
    163. # 计算估计评分
    164. return ratSimTotal/simTotal
    165. # recommend()函数,就是推荐引擎,它默认调用standEst()函数,产生了最高的N个推荐结果。
    166. # 如果不指定N的大小,则默认值为3。该函数另外的参数还包括相似度计算方法和估计方法
    167. def recommend(dataMat,user,N=3,simMeas=cosSim,estMethod=standEst):
    168. """svdEst( )
    169. Args:
    170. dataMat 训练数据集
    171. user 用户编号
    172. simMeas 相似度计算方法
    173. estMethod 使用的推荐算法
    174. Returns:
    175. 返回最终 N 个推荐结果
    176. """
    177. # 寻找未评级的物品
    178. # 对给定的用户建立一个未评分的物品列表
    179. unratedItems=nonzero(dataMat[user,:].A==0)[1]
    180. # 如果不存在未评分物品,那么就退出函数
    181. if len(unratedItems)==0:
    182. return 'you rated everything'
    183. # 物品的编号和评分值
    184. itemScores=[]
    185. # 在未评分物品上进行循环
    186. for item in unratedItems:
    187. # 获取 item 该物品的评分
    188. estimatedScore=estMethod(dataMat,user,simMeas,item)
    189. itemScores.append((item,estimatedScore))
    190. # 按照评分得分 进行逆排序,获取前N个未评级物品进行推荐
    191. return sorted(itemScores,key=lambda jj:jj[1],reverse=True)[:N]
    192. def analyse_data(Sigma, loopNum=20):
    193. """analyse_data(分析 Sigma 的长度取值)
    194. Args:
    195. Sigma Sigma的值
    196. loopNum 循环次数
    197. """
    198. # 总方差的集合(总能量值)
    199. Sig2 = Sigma**2
    200. SigmaSum = sum(Sig2)
    201. for i in range(loopNum):
    202. SigmaI = sum(Sig2[:i+1])
    203. '''
    204. 根据自己的业务情况,就行处理,设置对应的 Singma 次数
    205. 通常保留矩阵 80% ~ 90% 的能量,就可以得到重要的特征并取出噪声。
    206. '''
    207. print('主成分: %s, 方差占比: %s%%' % (format(i+1, '2.0f'), format(SigmaI/SigmaSum*100, '4.2f')))
    208. # 图像压缩函数
    209. # 加载并转换数据
    210. def imgLoadData(filename):
    211. myl=[]
    212. # 打开文本文件,并从文件以数组方式读入字符
    213. for line in open(filename).readlines():
    214. newRow=[]
    215. for i in range(32):
    216. newRow.append(int(line[i]))
    217. myl.append(newRow)
    218. # 矩阵调入后,就可以在屏幕上输出该矩阵
    219. myMat = mat(myl)
    220. return myMat
    221. # 打印矩阵
    222. def printMat(inMat, thresh=0.8):
    223. # 由于矩阵保护了浮点数,因此定义浅色和深色,遍历所有矩阵元素,当元素大于阀值时打印1,否则打印0
    224. for i in range(32):
    225. for k in range(32):
    226. if float(inMat[i, k]) > thresh:
    227. print(1, end=' ')
    228. else:
    229. print(0, end=' ')
    230. print('')
    231. # 实现图像压缩,允许基于任意给定的奇异值数目来重构图像
    232. def imgCompress(numSV=3, thresh=0.8):
    233. """imgCompress( )
    234. Args:
    235. numSV Sigma长度
    236. thresh 判断的阈值
    237. """
    238. # 构建一个列表
    239. myMat=imgLoadData('data/14.SVD/0_5.txt')
    240. print("****original matrix****")
    241. # 对原始图像进行SVD分解并重构图像e
    242. printMat(myMat, thresh)
    243. # 通过Sigma 重新构成SigRecom来实现
    244. # Sigma是一个对角矩阵,因此需要建立一个全0矩阵,然后将前面的那些奇异值填充到对角线上。
    245. U, Sigma, VT = la.svd(myMat)
    246. # SigRecon = mat(zeros((numSV, numSV)))
    247. # for k in range(numSV):
    248. # SigRecon[k, k] = Sigma[k]
    249. # 分析插入的 Sigma 长度
    250. analyse_data(Sigma, 20)
    251. SigRecon = mat(eye(numSV) * Sigma[: numSV])
    252. reconMat = U[:, :numSV] * SigRecon * VT[:numSV, :]
    253. print("****reconstructed matrix using %d singular values *****" % numSV)
    254. printMat(reconMat, thresh)
    1. # 对矩阵进行SVD分解(用python实现SVD)
    2. Data = loadExData()
    3. print ('Data:', Data)
    4. U, Sigma, VT = linalg.svd(Data)
    5. # 打印Sigma的结果,因为前3个数值比其他的值大了很多,为9.72140007e+00,5.29397912e+00,6.84226362e-01
    6. # 后两个值比较小,每台机器输出结果可能有不同可以将这两个值去掉
    7. print ('U:', U)
    8. print ('Sigma', Sigma)
    9. print ('VT:', VT)
    10. print ('VT:', VT.T)
    11. # 重构一个3x3的矩阵Sig3
    12. Sig3 = mat([[Sigma[0], 0, 0], [0, Sigma[1], 0], [0, 0, Sigma[2]]])
    13. print (U[:, :3] * Sig3 * VT[:3, :])
    1. # 计算欧氏距离
    2. myMat = mat(loadExData())
    3. # print myMat
    4. print (ecludSim(myMat[:, 0], myMat[:, 1]))
    5. print (ecludSim(myMat[:, 0], myMat[:, 0]))
    6. # 计算余弦相似度
    7. print (cosSim(myMat[:, 0], myMat[:, 1]))
    8. print (cosSim(myMat[:, 0], myMat[:, 0]))
    9. # 计算皮尔逊相关系数
    10. print (pearsSim(myMat[:, 0], myMat[:, 1]))
    11. print (pearsSim(myMat[:, 0], myMat[:, 0]))
    12. # 计算相似度的方法
    13. myMat = mat(loadExData3())
    14. # print myMat
    15. # 计算相似度的第一种方式
    16. print(recommend(myMat, 1, estMethod=svdEst))
    17. # 计算相似度的第二种方式
    18. print(recommend(myMat, 1, estMethod=svdEst, simMeas=pearsSim))
    19. # 默认推荐(菜馆菜肴推荐示例)
    20. print(recommend(myMat, 2))
    21. # 利用SVD提高推荐效果
    22. U, Sigma, VT = la.svd(mat(loadExData2()))
    23. print (Sigma) # 计算矩阵的SVD来了解其需要多少维的特征
    24. Sig2 = Sigma**2 # 计算需要多少个奇异值能达到总能量的90%
    25. print (sum(Sig2)) # 计算总能量
    26. print (sum(Sig2) * 0.9) # 计算总能量的90%
    27. print (sum(Sig2[: 2])) # 计算前两个元素所包含的能量
    28. print (sum(Sig2[: 3])) # 两个元素的能量值小于总能量的90%,于是计算前三个元素所包含的能量
    29. # 该值高于总能量的90%,这就可以了
    30. # 压缩图片
    31. imgCompress(3)

  • 相关阅读:
    vos3000外呼系统如何修改话机注册端口
    [npm] npx 介绍与使用说明
    ES系列二之常见问题解决
    真正的黑客,往往怀着一颗学徒的心!
    qt textedit图片缩放
    Daily Practice: Codeforces Round #816 (Div. 2)
    2022暑期训练题单(基本算法)Day1~2
    原生Javascript(数组操作方法总结)-更新
    【python】OpenCV—Statistics
    类型转换、常用运算符
  • 原文地址:https://blog.csdn.net/qq_36973725/article/details/133375569