पोर्टेबल डेटा फॉर्मेट में scipy sparse csr_matrix को सहेजें / लोड करें


80

आप csr_matrixएक पोर्टेबल प्रारूप में एक डरावना विरल को कैसे बचाते / लोड करते हैं ? पाइथन 2 (लिनक्स 64-बिट) पर चलने के लिए पाइथन 3 (विंडोज 64-बिट) पर स्किपी स्पार्स मैट्रिक्स बनाया गया है। प्रारंभ में, मैंने अचार (प्रोटोकॉल = 2 और fix_imports = True के साथ) का उपयोग किया था, लेकिन यह पायथन 3.2.2 (विंडोज 64-बिट) से पायथन 2.7.2 (विंडोज 32-बिट) तक जाने में काम नहीं आया और त्रुटि मिली:

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

अगला, कोशिश की numpy.saveऔर numpy.loadसाथ ही साथ scipy.io.mmwrite()और scipy.io.mmread()इन विधियों में से किसी ने भी काम नहीं किया।


2
mmwrite / mmread को काम करना चाहिए, क्योंकि यह एक टेक्स्ट फाइल फॉर्मेट है। लिनक्स बनाम विंडोज के साथ संभव मुद्दा लाइन एंडिंग, CRLF बनाम LF
pv हो सकता है।

जवाबों:


121

संपादित करें: SciPy 1.19 अब है scipy.sparse.save_npzऔर scipy.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। सभी सरल ndarrays हैं, इसलिए 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'])

3
किसी भी विचार अगर वहाँ कुछ कारण यह विरल मैट्रिक्स वस्तुओं में एक विधि के रूप में लागू नहीं किया गया था? Scipy.io.savemat विधि मज़बूती से काम करने के लिए पर्याप्त है, हालांकि ...
गणित

6
नोट: अगर save_sparse_csr में फ़ाइल नाम में एक्सटेंशन .npz नहीं है, तो यह अपने आप जुड़ जाएगा। यह स्वचालित रूप से load_sparse_csr फ़ंक्शन में नहीं किया गया है।
physicalattraction

@physicalattraction लोडर फंक्शन की शुरुआत में इसे जोड़ने का एक आसान उपाय हैif not filename.endswith('.npz'): filename += '.npz'
अलेक्जेंडर शचुर

11
Scipy 1.19 अब है scipy.sparse.save_npzऔर load
हंपुलज

3
@hpaulj यह सही उत्तर देने के लिए नए उपयोगकर्ताओं के लिए उपयोगी हो सकता है: संस्करण 0.19 है
पी। कैमिलेरी

37

यद्यपि आप लिखते हैं, scipy.io.mmwriteऔर scipy.io.mmreadआपके लिए काम नहीं करते हैं, मैं सिर्फ यह जोड़ना चाहता हूं कि वे कैसे काम करते हैं। यह सवाल नं। 1 Google ने हिट किया, इसलिए मैंने खुद को सरल और स्पष्ट स्केपी-कार्यों पर स्विच करने से पहले np.savezऔर साथ शुरू किया pickle.dump। वे मेरे लिए काम करते हैं और उन लोगों की देखरेख नहीं करनी चाहिए जिन्होंने उन्हें अभी तक कोशिश नहीं की है।

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)

क्या यह अन्य उत्तरों की तुलना में नवीनतम समाधान है?
दिनेशदीप

हाँ, वर्तमान में यह नवीनतम है। आप प्रश्न के नीचे टैब में सबसे पुराने पर क्लिक करके सृजन के समय तक उत्तर का आदेश दे सकते हैं ।
फ्रैंक जैल्को सेप

केवल लिखने पर यह विधि विफल हो जाती है import scipy। एक स्पष्ट from scipy import ioया import scipy.ioआवश्यक है।
१ots:०५ पर

1
यह np.savezऔर cPickleसमाधानों की तुलना में बहुत धीमी गति से काम करता है , और ~ 3x बड़ी फ़ाइल का उत्पादन करता है। परीक्षण विवरण के लिए कृपया मेरा उत्तर देखें।
डेनिस गोलोमाज़ोव

26

यहाँ Jupyter नोटबुक का उपयोग करके तीन सबसे उत्कीर्ण उत्तरों की प्रदर्शन तुलना है। इनपुट में घनत्व 0.001 के साथ 1M x 100K यादृच्छिक विरल मैट्रिक्स है, जिसमें 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.

(ध्यान दें कि प्रारूप को सीएसआर से सीओओ में बदल दिया गया है)।

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यहाँ विजेता है।


2
धन्यवाद! बस ध्यान दें कि कम से कम मेरे लिए (Py 2.7.11) लाइन from scipy.sparse import ioकाम नहीं करती है। इसके बजाय, बस करो from scipy import ioडॉक्स
पैट्रिक

1
@ अपडेट के लिए धन्यवाद। आयात परिवर्तन में किया जाना चाहिए था scipy
डेनिस गोलोमेज़ोव


11

यह मानते हुए कि आपके पास दोनों मशीनों पर चीर-फाड़ है, आप बस इस्तेमाल कर सकते हैं pickle

हालांकि, सुन्न सरणियों को चुनते समय एक बाइनरी प्रोटोकॉल निर्दिष्ट करना सुनिश्चित करें। अन्यथा आप एक बड़ी फ़ाइल के साथ हवा करेंगे।

किसी भी दर पर, आपको यह करने में सक्षम होना चाहिए:

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)

अचार का उपयोग करना मेरा मूल समाधान था (प्रोटोकॉल = 2 और fix_imports = True के साथ) लेकिन यह पायथन 3.2.2 से पायथन 2.7.2 तक जाने से काम नहीं करता था। सवाल करने के लिए इस जानकारी को जोड़ा है।
हेनरी थॉर्नटन

कृपया ध्यान दें कि, हालांकि यह सबसे तेज़ समाधान लगता है ( मेरे उत्तर में सरल परीक्षण के अनुसार ), cPickleबहुत बड़े मेट्रिसेस ( लिंक ) के साथ काम नहीं करता है ।
डेनिस गोलोमाज़ोव

9

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")

2

संपादित करें जाहिर है कि यह काफी सरल है:

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

जो एक ((i, j), value)टुपल्स का उत्पादन करेगा , जो कि धारावाहिक और डीज़रीलाइज़ करना आसान है। निश्चित नहीं है कि यह प्रदर्शन-वार की तुलना नीचे दिए गए कोड से कैसे करता है csr_matrix, लेकिन यह निश्चित रूप से सरल है। मैं नीचे मूल उत्तर छोड़ रहा हूं क्योंकि मुझे आशा है कि यह जानकारीपूर्ण है।


अपने दो सेंट जोड़ना: मेरे लिए, npzपोर्टेबल नहीं है क्योंकि मैं इसका उपयोग अपने मैट्रिक्स को गैर-पायथन ग्राहकों (जैसे कि पोस्टग्रेक्सेल - खुशी से सही होने के लिए) को आसानी से निर्यात करने के लिए नहीं कर सकता हूं। इसलिए मुझे स्पार्स मैट्रिक्स के लिए 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 गुना धीमा है , जो मैंने परीक्षण किया है।


1

यह वही है जो मैं एक को बचाने के लिए इस्तेमाल किया 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)

1

यह मेरे लिए काम करता है:

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 ऑब्जेक्ट सरणी को मूल ऑब्जेक्ट में बदलने के लिए कॉल करना था ।


0

मुझे एक सरल और सामान्य प्रारूप में मैट्रिक्स भेजने के लिए कहा गया था:

<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\n" % (nonZeros[0, entry], nonZeros[1, entry], m[nonZeros[0, entry], nonZeros[1, entry]]))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.