以可移植数据格式保存/加载 scipy sparse csr_matrix

2025-04-01 09:56:00
admin
原创
19
摘要:问题描述:如何以可移植格式保存/加载 scipy 稀疏矩阵csr_matrix?scipy 稀疏矩阵是在 Python 3(Windows 64 位)上创建的,以便在 Python 2(Linux 64 位)上运行。最初,我使用了 pickle(使用 protocol=2 和 fix_imports=True...

问题描述:

如何以可移植格式保存/加载 scipy 稀疏矩阵csr_matrix?scipy 稀疏矩阵是在 Python 3(Windows 64 位)上创建的,以便在 Python 2(Linux 64 位)上运行。最初,我使用了 pickle(使用 protocol=2 和 fix_imports=True),但这在从 Python 3.2.2(Windows 64 位)转换为 Python 2.7.2(Windows 32 位)时不起作用,并出现错误:

TypeError: ('data type not understood', <built-in function _reconstruct>, (<type 'numpy.ndarray'>, (0,), '[98]')).

接下来,尝试了numpy.savenumpy.load以及和scipy.io.mmwrite()scipy.io.mmread()但这些方法都没有起作用。


解决方案 1:

编辑: scipy 0.19 现在有scipy.sparse.save_npzscipy.sparse.load_npz

from scipy import sparse

sparse.save_npz("yourmatrix.npz", your_matrix)
your_matrix_back = sparse.load_npz("yourmatrix.npz")

对于这两个函数,file参数也可以是类似文件的对象(即的结果open),而不是文件名。


得到了Scipy用户组的答案:

csr_matrix 有 3 个重要的数据属性:.data.indices.indptr。 它们都是简单的 ndarray,因此numpy.save可以对它们进行操作。 使用numpy.save或保存这三个数组numpy.savez,使用 重新加载它们numpy.load,然后使用以下方法重新创建稀疏矩阵对象:

new_csr = csr_matrix((data, indices, indptr), shape=(M, N))

例如:

def save_sparse_csr(filename, array):
    np.savez(filename, data=array.data, indices=array.indices,
             indptr=array.indptr, shape=array.shape)

def load_sparse_csr(filename):
    loader = np.load(filename)
    return csr_matrix((loader['data'], loader['indices'], loader['indptr']),
                      shape=loader['shape'])

解决方案 2:

尽管您写的scipy.io.mmwritescipy.io.mmread对您不起作用,但我只想补充一下它们的工作原理。这个问题是 Google 上排名第一的热门问题,所以我自己先从和开始np.savezpickle.dump然后再切换到简单而明显的 scipy 函数。它们对我有用,那些还没有尝试过它们的人不应该忽视它们。

from scipy import sparse, io

m = sparse.csr_matrix([[0,0,0],[1,0,0],[0,1,0]])
m              # <3x3 sparse matrix of type '<type 'numpy.int64'>' with 2 stored elements in Compressed Sparse Row format>

io.mmwrite("test.mtx", m)
del m

newm = io.mmread("test.mtx")
newm           # <3x3 sparse matrix of type '<type 'numpy.int32'>' with 2 stored elements in COOrdinate format>
newm.tocsr()   # <3x3 sparse matrix of type '<type 'numpy.int32'>' with 2 stored elements in Compressed Sparse Row format>
newm.toarray() # array([[0, 0, 0], [1, 0, 0], [0, 1, 0]], dtype=int32)

解决方案 3:

以下是使用 Jupyter 笔记本对三个得票最多的答案进行的性能比较。输入是一个 1M x 100K 随机稀疏矩阵,密度为 0.001,包含 100M 个非零值:

from scipy.sparse import random
matrix = random(1000000, 100000, density=0.001, format='csr')

matrix
<1000000x100000 sparse matrix of type '<type 'numpy.float64'>'
with 100000000 stored elements in Compressed Sparse Row format>

io.mmwrite/io.mmread

from scipy.sparse import io

%time io.mmwrite('test_io.mtx', matrix)
CPU times: user 4min 37s, sys: 2.37 s, total: 4min 39s
Wall time: 4min 39s

%time matrix = io.mmread('test_io.mtx')
CPU times: user 2min 41s, sys: 1.63 s, total: 2min 43s
Wall time: 2min 43s    

matrix
<1000000x100000 sparse matrix of type '<type 'numpy.float64'>'
with 100000000 stored elements in COOrdinate format>    

Filesize: 3.0G.

(请注意,格式已从 csr 更改为 coo)。

np.savez/np.load

import numpy as np
from scipy.sparse import csr_matrix

def save_sparse_csr(filename, array):
    # note that .npz extension is added automatically
    np.savez(filename, data=array.data, indices=array.indices,
             indptr=array.indptr, shape=array.shape)

def load_sparse_csr(filename):
    # here we need to add .npz extension manually
    loader = np.load(filename + '.npz')
    return csr_matrix((loader['data'], loader['indices'], loader['indptr']),
                      shape=loader['shape'])


%time save_sparse_csr('test_savez', matrix)
CPU times: user 1.26 s, sys: 1.48 s, total: 2.74 s
Wall time: 2.74 s    

%time matrix = load_sparse_csr('test_savez')
CPU times: user 1.18 s, sys: 548 ms, total: 1.73 s
Wall time: 1.73 s

matrix
<1000000x100000 sparse matrix of type '<type 'numpy.float64'>'
with 100000000 stored elements in Compressed Sparse Row format>

Filesize: 1.1G.

cPickle

import cPickle as pickle

def save_pickle(matrix, filename):
    with open(filename, 'wb') as outfile:
        pickle.dump(matrix, outfile, pickle.HIGHEST_PROTOCOL)
def load_pickle(filename):
    with open(filename, 'rb') as infile:
        matrix = pickle.load(infile)    
    return matrix    

%time save_pickle(matrix, 'test_pickle.mtx')
CPU times: user 260 ms, sys: 888 ms, total: 1.15 s
Wall time: 1.15 s    

%time matrix = load_pickle('test_pickle.mtx')
CPU times: user 376 ms, sys: 988 ms, total: 1.36 s
Wall time: 1.37 s    

matrix
<1000000x100000 sparse matrix of type '<type 'numpy.float64'>'
with 100000000 stored elements in Compressed Sparse Row format>

Filesize: 1.1G.

注意:cPickle 不适用于非常大的对象(请参阅此答案)。根据我的经验,它不适用于具有 270M 个非零值的 2.7M x 50k 矩阵。
np.savez解决方案效果很好。

结论

(基于这个针对 CSR 矩阵的简单测试)
cPickle是最快的方法,但它不适用于非常大的矩阵,np.savez速度只是稍微慢一点,而速度io.mmwrite要慢得多,生成的文件更大,并且恢复为错误的格式。所以np.savez是这里的赢家。

解决方案 4:

现在您可以使用scipy.sparse.save_npz
https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.save_npz.html

解决方案 5:

假设你的两台机器上都有 scipy,那么你就可以使用pickle

但是,在 pickle numpy 数组时一定要指定二进制协议。否则,您最终会得到一个巨大的文件。

无论如何,你应该能够做到这一点:

import cPickle as pickle
import numpy as np
import scipy.sparse

# Just for testing, let's make a dense array and convert it to a csr_matrix
x = np.random.random((10,10))
x = scipy.sparse.csr_matrix(x)

with open('test_sparse_array.dat', 'wb') as outfile:
    pickle.dump(x, outfile, pickle.HIGHEST_PROTOCOL)

然后你可以使用以下命令加载它:

import cPickle as pickle

with open('test_sparse_array.dat', 'rb') as infile:
    x = pickle.load(infile)

解决方案 6:

从 scipy 0.19.0 开始,您可以通过以下方式保存和加载稀疏矩阵:

from scipy import sparse

data = sparse.csr_matrix((3, 4))

#Save
sparse.save_npz('data_sparse.npz', data)

#Load
data = sparse.load_npz("data_sparse.npz")

解决方案 7:

编辑显然它足够简单:

def sparse_matrix_tuples(m):
    yield from m.todok().items()

这将产生一个((i, j), value)元组,这些元组易于序列化和反序列化。不确定它在性能方面与下面的代码相比如何csr_matrix,但它肯定更简单。我将原始答案保留在下面,因为我希望它能提供信息。


补充一下我的看法:对我来说,npz它不可移植,因为我不能用它轻松地将矩阵导出到非 Python 客户端(例如 PostgreSQL——很高兴得到纠正)。所以我本来希望获得稀疏矩阵的 CSV 输出(就像您获得print()稀疏矩阵一样)。如何实现这一点取决于稀疏矩阵的表示。对于 CSR 矩阵,以下代码会输出 CSV 输出。您可以适应其他表示。

import numpy as np

def csr_matrix_tuples(m):
    # not using unique will lag on empty elements
    uindptr, uindptr_i = np.unique(m.indptr, return_index=True)
    for i, (start_index, end_index) in zip(uindptr_i, zip(uindptr[:-1], uindptr[1:])):
        for j, data in zip(m.indices[start_index:end_index], m.data[start_index:end_index]):
            yield (i, j, data)

for i, j, data in csr_matrix_tuples(my_csr_matrix):
    print(i, j, data, sep=',')

save_npz据我测试,它比当前实现慢约 2 倍。

解决方案 8:

这是我用来保存的lil_matrix

import numpy as np
from scipy.sparse import lil_matrix

def save_sparse_lil(filename, array):
    # use np.savez_compressed(..) for compression
    np.savez(filename, dtype=array.dtype.str, data=array.data,
        rows=array.rows, shape=array.shape)

def load_sparse_lil(filename):
    loader = np.load(filename)
    result = lil_matrix(tuple(loader["shape"]), dtype=str(loader["dtype"]))
    result.data = loader["data"]
    result.rows = loader["rows"]
    return result

我必须说我发现 NumPy 的 np.load(..) 非常。这是我目前的解决方案,我觉得运行速度要快得多:

from scipy.sparse import lil_matrix
import numpy as np
import json

def lil_matrix_to_dict(myarray):
    result = {
        "dtype": myarray.dtype.str,
        "shape": myarray.shape,
        "data":  myarray.data,
        "rows":  myarray.rows
    }
    return result

def lil_matrix_from_dict(mydict):
    result = lil_matrix(tuple(mydict["shape"]), dtype=mydict["dtype"])
    result.data = np.array(mydict["data"])
    result.rows = np.array(mydict["rows"])
    return result

def load_lil_matrix(filename):
    result = None
    with open(filename, "r", encoding="utf-8") as infile:
        mydict = json.load(infile)
        result = lil_matrix_from_dict(mydict)
    return result

def save_lil_matrix(filename, myarray):
    with open(filename, "w", encoding="utf-8") as outfile:
        mydict = lil_matrix_to_dict(myarray)
        json.dump(mydict, outfile)

解决方案 9:

这对我有用:

import numpy as np
import scipy.sparse as sp
x = sp.csr_matrix([1,2,3])
y = sp.csr_matrix([2,3,4])
np.savez(file, x=x, y=y)
npz = np.load(file)

>>> npz['x'].tolist()
<1x3 sparse matrix of type '<class 'numpy.int64'>'
    with 3 stored elements in Compressed Sparse Row format>

>>> npz['x'].tolist().toarray()
array([[1, 2, 3]], dtype=int64)

诀窍是调用.tolist()将形状 0 对象数组转换为原始对象。

解决方案 10:

我被要求以简单通用的格式发送矩阵:

<x,y,value>

我最终得到了这个:

def save_sparse_matrix(m,filename):
    thefile = open(filename, 'w')
    nonZeros = np.array(m.nonzero())
    for entry in range(nonZeros.shape[1]):
        thefile.write("%s,%s,%s
" % (nonZeros[0, entry], nonZeros[1, entry], m[nonZeros[0, entry], nonZeros[1, entry]]))
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2157  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1470  
  引言PLM(产品生命周期管理)项目在企业的产品创新与发展中扮演着至关重要的角色。有效的资源平衡技术是确保PLM项目顺利推进、达成预期目标的关键因素。随着时代的发展,到2025年,资源分配矩阵与敏捷迭代的协同模式将为PLM项目带来全新的活力与挑战。资源分配矩阵能够清晰地规划不同阶段、不同任务所需的各类资源,使资源配置更加...
plm系统简介   7  
  产品生命周期管理(Product Lifecycle Management,PLM)是企业管理产品从概念设计到退役全流程的重要手段。随着市场竞争的加剧和技术的飞速发展,优化产品生命周期管理流程对于企业提升效率、降低成本、增强创新能力至关重要。PLM 软件作为实现高效产品生命周期管理的关键工具,其合理运用与优化能够为企业...
plm产品生命周期管理系统   9  
  产品生命周期管理(Product Lifecycle Management,简称PLM)对于企业的发展至关重要。它涵盖了产品从概念产生到最终退役的全过程,涉及到多个部门和环节。有效的产品生命周期管理能够提升产品质量、缩短研发周期、降低成本,从而增强企业的市场竞争力。而PLM软件作为实现高效产品生命周期管理的重要工具,如...
三大plm软件   5  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用