zoukankan      html  css  js  c++  java
  • scipy.sparse求稀疏矩阵前k个特征值

    scipy.sparse求稀疏矩阵前k个特征值 - Waleking的专栏 - 博客频道 - CSDN.NET

    scipy.sparse求稀疏矩阵前k个特征值

    分类: python 机器学习 448人阅读 评论(0) 收藏 举报
     

    背景:

    要在python中处理7000*7000的稀疏矩阵,计算前k小的特征值和相应的特征向量。不想在matlab中做这件事了,所有的数据预处理和展现工作都想在python中完成。然而一般的linalg提供的eig开销太大,要计算所有的特征值和特征向量,这个开销要达到 O(N^3),对于谱聚类来说,这个开销是不能忍受的。

    所以要借助稀疏矩阵计算的工具包。

    探索过程:

    使用scipy.sparse

    对于10*10大小的矩阵都没有问题:

    1. import scipy as sp    
    2. import scipy.sparse.linalg    
    3. import bumpy as np    
    4. vals, vecs = sp.sparse.linalg.eigs(np.identity(10), k=6)  

    但是对于100*100的矩阵就出错了:

    1. vals, vecs = sp.sparse.linalg.eigs(np.identity(100), k=6)  

    过程当中总是出现错误:

    ArpackError: ARPACK error 3: No shifts could be applied during a cycle of the Implicitly restarted Arnoldi iteration. One possibility is to increase the size of NCV relative to NEV

    查看了一下源代码,发现求特征值的方法引用了:

    ARPACK USERS GUIDE: Solution of Large Scale Eigenvalue Problems by Implicitly Restarted  Arnoldi Methods

    文章在这里 http://people.sc.fsu.edu/~jburkardt/pdf/arpack.pdf  scipy.sparse.linalg引用它大意是说使用了Arnoldi方法求大规模矩阵的特征值问题。

    查阅了一下手册,那个ArpackError错误的意思是要修改参数。

    既然是这样,就查看一下scipy.sparse的手册吧 http://docs.scipy.org/doc/scipy/reference/sparse.html

    里面介绍了几种类型的稀疏矩阵,sp.sparse.linalg.eigs的参数也应该是稀疏矩阵,于是修改了代码:

    1. import scipy as sp  
    2. import scipy.sparse.linalg  
    3. import numpy as np  
    4. import time  
    5. A = sp.sparse.lil_matrix((1000010000))  
    6. A[0,:1000]=np.random.rand(1000)  
    7. A.setdiag(np.random.rand(10000))                                                                                                                               
    8. timeCheckin=time.clock()  
    9. vals, vecs = sp.sparse.linalg.eigs(A, k=3)  
    10. print("first 6 eigenvaluse cost %s" % (time.clock()-timeCheckin))  
    11. print vals  

    构造了一个10000*10000的矩阵,第一行,第二行,第四行有 [0,1]上均匀分布的随机数。计算前3个特征值,耗时52.091 s. 又做了一次实验,因随机性,这次耗时314.156s,初步判断是和算法的收敛状况有关。
    需要说明的是,如果对稀疏矩阵直接用矩阵的乘法运算,如dot(A,vecs[:,0]) 就会非常悲剧,貌似稀疏矩阵会完全展开成普通矩阵计算,在mac上运行了10个小时,内存最高峰时使用2.84GB,即便这样还是没有得到结果(不过证明了64位python的鲁棒性)。

    另外使用MATLAB做对比,matlab代码是

    1. d=rand(10000,1)  
    2. A=diag(d)  
    3. A[1,1:1000]=rand(1,1000)  
    4. eigs(A,3)  

    查手册,是用Ritz方法,迭代了965次收敛,耗时30min。

    但如果也让MATLAB对稀疏矩阵做操作,那么它也调用ARPACK工具包,也就是说和scipy.sparse是一样的,精度上没有区别,计算速度也和python的相当。

    另外可以考虑pysparse:

    这里是PySparse的官方网站

    http://pysparse.sourceforge.net/spmatrix.html#vectorization

    最终解决方案:

    1. #coding=utf8  
    2. import scipy as sp  
    3. import scipy.sparse.linalg  
    4. import scipy.io as sio   
    5. import numpy as np  
    6. import time  
    7. import os  
    8. def generateTestMat(size):  
    9.         '''''generate a test matrix for k-eigenvalues problem 
    10.         '  matlab and scipy.sparse.linalg.eigs seem use the same package ARPACK 
    11.         '  this matrix has two diagnol lines, one is on the diagnol and the other is off 1 
    12.         '''  
    13.         A = sp.sparse.lil_matrix((size, size))  
    14.         A[0,:size]=np.random.rand(size)  
    15.         A.setdiag(np.random.rand(size))  
    16.         A.setdiag(np.random.rand(size-1),1)  
    17.         #保存成matlab可以读取的格式,{"A":A}前面的A表示在matlab中的名字,后面的A表示在python中名字  
    18.         sio.savemat("A.mat",{"A":A},oned_as='row')  
    19.         print("generate a test matrix,with size %s by %s" %(size,size))  
    20.   
    21. def calculateKEigs(tolerance=0):  
    22.         if(os.path.exists(os.getcwd()+"/"+"A.mat")==False):  
    23.                 generateTestMat()  
    24.         A=sio.loadmat("A.mat")["A"]#后面的A表示在matlab中名字  
    25.         timeCheckin=time.clock()  
    26.         #tol=0表示使用原先的计算精度  
    27.         vals, vecs = sp.sparse.linalg.eigs(A, k=3,tol=tolerance,which="SM")  
    28.         print("first 3 eigenvalues cost %s seconds" % (time.clock()-timeCheckin))  
    29.         print("first 3 eigenvalues are %s" % vals)  
    30.         k=len(vals)  
    31.         nRow,nCol=A.get_shape()  
    32.         for i in range(0,k):  
    33.                 print("error of lamda is %s " % (np.linalg.norm(A.dot(vecs[:,i])-vals[i]*vecs[:,i])))  
    34.         for i in range(0,k):  
    35.                 v=np.random.rand(nCol)  
    36.                 #v must be normalization  
    37.                 v=v/np.linalg.norm(v)  
    38.                 print("random error is %s " % (np.linalg.norm(A.dot(v)-vals[i]*v)))  
    39.   
    40. generateTestMat(10000)  
    41. calculateKEigs(tolerance=0.001)  

    结果如下,还是相当好的——10000*10000的矩阵耗时32.58秒,求出前3小的特征值,计算精度为0.001:

    generate a test matrix,with size 10000 by 10000
    first 3 eigenvalues cost 32.576715 seconds
    first 3 eigenvalues are [-0.00547908+0.00513399j -0.00547908-0.00513399j -0.00547640+0.00724066j]
    error of lamda is 3.44171050491e-06 
    error of lamda is 3.44171050491e-06 
    error of lamda is 7.36171280591e-06 
    random error is 43.5130937694 
    random error is 43.3207057797 

    random error is 43.3430705168

  • 相关阅读:
    oracle改表语句
    pr视频过渡效果
    远程桌面连接
    kill-power
    Leetcode 466.统计重复个数
    Leetcode 464.我能赢吗
    Leetcode 462.最少移动次数使数组元素相等
    Leetcode 459.重复的子字符串
    Leetcode 458.可怜的小猪
    Leetcode 457.环形数组循环
  • 原文地址:https://www.cnblogs.com/lexus/p/2816024.html
Copyright © 2011-2022 走看看