【问题标题】:Load sparse array from npy file从 npy 文件加载稀疏数组
【发布时间】:2011-09-11 01:33:31
【问题描述】:

我正在尝试加载我之前保存的稀疏数组。保存稀疏数组很容易。尝试阅读它虽然是一种痛苦。 scipy.load 在我的稀疏数组周围返回一个 0d 数组。

import scipy as sp
A = sp.load("my_array"); A
array(<325729x325729 sparse matrix of type '<type 'numpy.int8'>'
with 1497134 stored elements in Compressed Sparse Row format>, dtype=object)

为了得到一个稀疏矩阵,我必须将 0d 数组展平,或者使用 sp.asarray(A)。这似乎是一种非常困难的做事方式。 Scipy 是否足够聪明,可以理解它已经加载了一个稀疏数组?有没有更好的加载稀疏数组的方法?

【问题讨论】:

    标签: python scipy sparse-array


    【解决方案1】:

    对于mmwrite 答案的所有赞成票,我很惊讶没有人试图回答实际问题。不过既然重启了,那我试试看。

    这再现了 OP 案例:

    In [90]: x=sparse.csr_matrix(np.arange(10).reshape(2,5))
    In [91]: np.save('save_sparse.npy',x)
    In [92]: X=np.load('save_sparse.npy')
    In [95]: X
    Out[95]: 
    array(<2x5 sparse matrix of type '<type 'numpy.int32'>'
        with 9 stored elements in Compressed Sparse Row format>, dtype=object)
    In [96]: X[()].A
    Out[96]: 
    array([[0, 1, 2, 3, 4],
           [5, 6, 7, 8, 9]])
    
    In [93]: X[()].A
    Out[93]: 
    array([[0, 1, 2, 3, 4],
           [5, 6, 7, 8, 9]])
    In [94]: x
    Out[94]: 
    <2x5 sparse matrix of type '<type 'numpy.int32'>'
        with 9 stored elements in Compressed Sparse Row format
    

    `user4713166 给我们的[()] 并不是提取稀疏数组的“硬方法”。

    np.save 和 np.load 设计用于在 ndarray 上运行。但是稀疏矩阵不是这样的数组,也不是子类(就像np.matrix 一样)。 np.save 似乎将非数组对象包装在 object dtype array 中,并将其与对象的腌制形式一起保存。

    当我尝试保存另一种无法腌制的对象时,我在以下位置收到错误消息:

    403  # We contain Python objects so we cannot write out the data directly.
    404  # Instead, we will pickle it out with version 2 of the pickle protocol.
    

    --> 405 pickle.dump(array, fp, protocol=2)

    所以回答Is Scipy smart enough to understand that it has loaded a sparse array?,不。 np.load 不知道稀疏数组。但是np.save 足够聪明,可以在给定不是数组的东西时下注,而np.load 会根据在文件中找到的内容尽其所能。

    关于保存和加载稀疏数组的替代方法,已经提到了io.savemat,MATLAB 兼容方法。这将是我的第一选择。但是这个例子也表明你可以使用普通的 Python pickling。如果您需要保存特定的稀疏格式,那可能会更好。如果您可以接受[()] 提取步骤,np.save 也不错。 :)


    https://github.com/scipy/scipy/blob/master/scipy/io/matlab/mio5.py write_sparse - 稀疏以csc 格式保存。除了标题之外,它还保存A.indices.astype('i4'))、A.indptr.astype('i4'))、A.data.real 和可选的A.data.imag。


    在快速测试中,我发现np.save/load 处理所有稀疏格式,除了dok,load 抱怨缺少shape。否则我在稀疏文件中找不到任何特殊的酸洗代码。

    【讨论】:

      【解决方案2】:

      可以使用 () 作为索引提取隐藏在 0d 数组中的对象:

      A = sp.load("my_array")[()]
      

      这看起来很奇怪,但它似乎仍然有效,而且它是一个非常短的解决方法。

      【讨论】:

      • 我很确定你也可以使用 .item(),但不要引用我的话 :)
      【解决方案3】:

      scipy.io 中的mmwrite/mmread 函数可以保存/加载矩阵市场格式的稀疏矩阵。

      scipy.io.mmwrite('/tmp/my_array',x)
      scipy.io.mmread('/tmp/my_array').tolil()    
      

      mmwrite 和 mmread 可能就是您所需要的。它经过充分测试并使用众所周知的格式。

      但是,以下可能会更快一些:

      我们可以将行列坐标和数据保存为 npz 格式的一维数组。

      import random
      import scipy.sparse as sparse
      import scipy.io
      import numpy as np
      
      def save_sparse_matrix(filename,x):
          x_coo=x.tocoo()
          row=x_coo.row
          col=x_coo.col
          data=x_coo.data
          shape=x_coo.shape
          np.savez(filename,row=row,col=col,data=data,shape=shape)
      
      def load_sparse_matrix(filename):
          y=np.load(filename)
          z=sparse.coo_matrix((y['data'],(y['row'],y['col'])),shape=y['shape'])
          return z
      
      N=20000
      x = sparse.lil_matrix( (N,N) )
      for i in xrange(N):
          x[random.randint(0,N-1),random.randint(0,N-1)]=random.randint(1,100)
      
      save_sparse_matrix('/tmp/my_array',x)
      load_sparse_matrix('/tmp/my_array.npz').tolil()
      

      这里有一些代码建议将稀疏矩阵保存在 npz 文件中 可能比使用 mmwrite/mmread 更快:

      def using_np_savez():    
          save_sparse_matrix('/tmp/my_array',x)
          return load_sparse_matrix('/tmp/my_array.npz').tolil()
      
      def using_mm():
          scipy.io.mmwrite('/tmp/my_array',x)
          return scipy.io.mmread('/tmp/my_array').tolil()    
      
      if __name__=='__main__':
          for func in (using_np_savez,using_mm):
              y=func()
              print(repr(y))
              assert(x.shape==y.shape)
              assert(x.dtype==y.dtype)
              assert(x.__class__==y.__class__)    
              assert(np.allclose(x.todense(),y.todense()))
      

      产量

      % python -mtimeit -s'import test' 'test.using_mm()'
      10 loops, best of 3: 380 msec per loop
      
      % python -mtimeit -s'import test' 'test.using_np_savez()'
      10 loops, best of 3: 116 msec per loop
      

      【讨论】:

      • +1, scipy.io 是正确的解决方案。我要补充一点,如果你想走优化之路,你可以考虑numpy.load(mmap_mode='r'/'c')。从磁盘对文件进行内存映射可以提供即时加载并且可以节省内存,因为同一个内存映射数组可以在多个进程之间共享。
      • scipy.io.savemat 可能是最好的
      • 使用 np_savez 而不是 mm 将我的大型稀疏矩阵的加载时间从 8min47 减少到 3s !谢谢 !我也试过 savez_compressed 但大小相同,加载时间更长。
      猜你喜欢
      • 2021-04-27
      • 2016-02-16
      • 1970-01-01
      • 2021-11-25
      • 2018-08-22
      • 1970-01-01
      • 2011-02-02
      • 2020-11-22
      • 1970-01-01
      相关资源
      最近更新 更多