Migration von spmatrix zu sparray#
Dieses Dokument bietet Anleitungen zur Konvertierung von Code von sparse Matrizen zu sparse Arrays in scipy.sparse.
Die Änderung von sparse Matrizen zu sparse Arrays spiegelt die Konvertierung von np.matrix zu np.ndarray wider. Im Wesentlichen müssen wir von einem ausschließlich auf 2D-Matrixmultiplikation zentrierten matrix-Objekt zu einem 1D- oder 2D-"Array"-Objekt wechseln, das den Matrixmultiplikationsoperator und elementweise Berechnungen unterstützt.
Notation: Für diese Anleitung bezeichnen wir die sparse Array-Klassen allgemein als sparray und die sparse Matrix-Klassen als spmatrix. Dichte NumPy-Arrays werden als np.ndarray und dichte Matrixklassen als np.matrix bezeichnet. Unterstützte sparse Formate werden als BSR, COO, CSC, CSR, DIA, DOK, LIL bezeichnet und alle Formate werden sowohl von sparray als auch von spmatrix unterstützt. Der Begriff sparse bezieht sich auf entweder sparray oder spmatrix, während dense sich auf entweder np.ndarray oder np.matrix bezieht.
Überblick und Gesamtbild#
Die Konstruktor-Namen
*_matrix, z.B.csr_matrix, werden in*_arraygeändert.Eine spmatrix
Mist immer 2D (Zeilen x Spalten), selbst bei z.B.M.min(axis=0). Eine sparrayAkann 1D oder 2D sein. NumPy-Skalare werden für vollständige (0D) Reduktionen zurückgegeben, d.h.M.min().Das Iterieren über ein sparray ergibt 1D-sparrays. Das Iterieren über spmatrix ergibt 2D-sparse Matrizen.
Operatoren, die ihr Verhalten ändern, sind:
*, @, *=, @=, **Skalare Multiplikation, z.B.
5 * A, verwendet*, und5 @ Aist nicht implementiert.sparrays verwenden
*für elementweise Multiplikation und@für Matrixmultiplikation, während spmatrices entweder den Operator*oder@für Matrixmultiplikation verwenden. Beide könnenA.multiply(B)für elementweise Multiplikation verwenden.Skalare Exponenten, z.B.
A**2, verwenden elementweise Potenz für sparray und Matrixpotenz für spmatrix. Matrixpotenz für sparrays verwendetscipy.sparse.linalg.matrix_power(A, n).
Wenn Index-Arrays an die Konstruktorfunktionen übergeben werden, wählt spmatrix einen dtype basierend auf dem dtype und den Werten der eingehenden Arrays aus, während sparray nur den dtype der eingehenden Arrays berücksichtigt. Zum Beispiel ergibt
M=csr_matrix((data, indices, indptr))einenint32dtype fürM.indices, solange die Werte inindicesundindptrklein sind, auch wenn derdtypeder eingehenden Arraysint64ist. Im Gegensatz dazu ergibtA=csr_array((data, indices, indptr))einenint64dtype fürA.indices, wenn die Eingabearraysint64sind. Dies liefert vorhersagbarere, oft größere Index-dtypes in sparrays und weniger Casting zur Anpassung der dtypes.Überprüfung des sparse Typs und Formats
issparse(A)gibtTruefür jedes sparse Array/Matrix zurück.isspmatrix(M)gibtTruefür jede sparse Matrix zurück.isspmatrix_csr(M)prüft auf eine sparse Matrix mit spezifischem Format. Sie sollte durch eine Array-kompatible Version ersetzt werden, wie z.B.:issparse(A) and A.format == 'csr', was auf ein CSR sparse Array/Matrix prüft.
Umgang mit der API Ihres Softwarepakets mit sparse Ein-/Ausgabe
Die Eingaben sind relativ einfach, um sie mit spmatrix oder sparray zum Laufen zu bringen. Solange Sie
A.multiply(B)für elementweise undA @ Bfür Matrixmultiplikation verwenden undsparse.linalg.matrix_powerfür Matrixpotenzen verwenden, sollten Sie nach Abschluss des "ersten Durchlaufs" der im nächsten Abschnitt beschriebenen Migrationsschritte in Ordnung sein. Ihr Code wird beide Arten von Eingaben austauschbar verarbeiten.Die Migration von sparse Ausgaben aus Ihren Funktionen erfordert etwas mehr Überlegung. Erstellen Sie eine Liste aller Ihrer öffentlichen Funktionen, die spmatrix-Objekte zurückgeben. Prüfen Sie, ob Sie auch sparrays zurückgeben möchten. Das hängt von Ihrer Bibliothek und ihren Benutzern ab. Wenn Sie möchten, dass diese Funktionen weiterhin spmatrix- oder sparray-Objekte zurückgeben, können Sie dies oft mit einer sparse Eingabe tun, die auch als Signal für den zurückzugebenden Typ dient. Entwerfen Sie Ihre Funktion so, dass sie den eingegebenen Typ zurückgibt. Dieser Ansatz kann auf dichte Eingaben erweitert werden. Wenn die Eingabe eine np.matrix oder ein maskiertes Array mit np.matrix als seinem
._baseclassAttribut ist, geben Sie spmatrix zurück. Andernfalls geben Sie ein sparray zurück. Ohne solche Eingaben sind zwei weitere Ansätze, ein Schlüsselwortargument zu erstellen, um anzugeben, welches zurückgegeben werden soll, oder eine neue Funktion zu erstellen (wie wir es z.B. miteye_arraygetan haben), die die gleiche grundlegende Syntax hat, aber ein sparray zurückgibt. Welche Methode Sie wählen, hängt von Ihrer Bibliothek, Ihren Benutzern und Ihren Präferenzen ab.
Empfohlene Schritte für die Migration#
Erster Durchlauf (spmatrix im Code belassen)
Ändern Sie in Ihrem spmatrix-Code
*zu@für Matrixmultiplikation. Beachten Sie, dass die skalare Multiplikation mit sparse*verwenden sollte. (Siehe Hilfscode Tests verwenden, um * und ** Stellen zu finden unten)Matrixpotenzen, z.B.
M**3, sollten inscipy.sparse.linalg.matrix_power(A, 3)konvertiert werden.Implementieren Sie Alternativen zu nicht unterstützten Funktionen/Methoden wie
A.getnnz()->A.nnz(siehe Entfernte Methoden und Attribute unten).Ändern Sie alle Logiken bezüglich
issparse()undisspmatrix()nach Bedarf. Normalerweise bedeutet dies,isspmatrixdurchissparsezu ersetzen undisspmatrix_csr(G)durchissparse(G) and G.format == "csr". Außerdem wirdisspmatrix_csr(G) or isspmatrix_csc(G)zuissparse(G) and G.format in ['csr', 'csc']. Das Git-Such-Idiomgit grep 'isspm[a-z_]*('kann helfen, diese zu finden.Konvertieren Sie alle
spdiagsAufrufe zudia_matrix. Siehe Dokumentation inspdiags. Eine Suche nachspdiagsist alles, was Sie hier brauchen.Führen Sie alle Ihre Tests mit dem resultierenden Code aus. Sie verwenden immer noch spmatrix, nicht sparray. Aber Ihr Code und Ihre Tests sind für die Umstellung vorbereitet und Sie sollten sparrays als Eingabe für Ihren Code akzeptieren können und sie funktionieren meistens "einfach so".
Zweiter Durchlauf (Umstellung auf sparray)
Konvertieren Sie Konstruktorfunktionen wie
diagsundtriuin die Array-Version (siehe Details: Konstruktorfunktionen unten).Benennen Sie alle
*_matrixKonstruktoraufrufe in*_arrayum.Überprüfen Sie alle Funktionen/Methoden, für die die Migration zu 1D-Rückgabewerten führt. Dies sind hauptsächlich Indexierung und die Reduktionsfunktionen (siehe Details: Formänderungen und Reduktionen unten).
Überprüfen Sie alle Stellen, an denen Sie über spmatrices iterieren, und ändern Sie sie so, dass sie berücksichtigen, dass sparrays 1D-sparrays anstelle von 2D-spmatrices liefern.
Suchen und ändern Sie Stellen, an denen Ihr Code
np.matrix-Funktionen verwendet. Konvertieren Sie diese zunp.ndarray-Funktionen.Wenn Ihr Code sparse Daten aus Dateien mit
mmread,hb_readoderloadmatliest, verwenden Sie das neue Schlüsselwortargumentspmatrix=Falsein diesen Funktionen, um zu sparray zu lesen.Wenn Sie sparse Bibliotheken verwenden, die nur
int32Index-Arrays für sparse Darstellungen akzeptieren, empfehlen wir die Just-in-Time-Konvertierung. Konvertieren Sie zuint32kurz bevor Sie den Code aufrufen, derint32benötigt.sparraywählt den Index-dtype basierend auf dem dtype des Eingabearrays anstelle der Werte im Array aus. Wenn Sie also möchten, dass Ihre Index-Arraysint32sind, müssen Sie sicherstellen, dass jeder Index-Array wieindptr, den Sie ancsr_arrayübergeben, einenint32dtype hat. Beispmatrixist es verlockend, den Standard-int64-dtype fürnumpy-Arrays zu verwenden und sich darauf zu verlassen, dass der sparse Konstruktor bei Bedarf auf int32 herunterskaliert. Aber dieses Herunterskalieren führt zu zusätzlichem Neukastieren bei der Arbeit mit anderen Matrizen, Slices oder arithmetischen Ausdrücken. Fürsparraykönnen Sie sich immer noch darauf verlassen, dass die Konstruktoren dtypes auswählen. Aber Sie haben auch die Möglichkeit, Ihren Index-dtype über den dtype der eingehenden Index-Arrays anstelle ihrer Werte zu wählen. Wenn Sie alsoint32möchten, setzen Sie den dtype, z.B.indices = np.array([1,3,6], dtype=np.int32)oderindptr = np.arange(9, dtype=np.int32), wenn Sie die Index-Arrays erstellen. Siehe Index-Array-Dtypes unten für weitere Informationen. In vielen Fällen ist der Index-Array-dtype nicht entscheidend, und Sie können die Konstruktoren den dtype sowohl für sparray als auch für spmatrix auswählen lassen.Testen Sie Ihren Code. Und **lesen** Sie Ihren Code. Sie haben auf sparray migriert.
Details: Konstruktorfunktionen#
Diese vier Funktionen sind neu und verarbeiten nur sparrays: block_array, diags_array, eye_array und random_array. Ihre Signaturen sind
def block_array(blocks, format=None, dtype=None):
def diags_array(diagonals, /, *, offsets=0, shape=None, format=None, dtype=None):
def eye_array(m, n=None, *, k=0, dtype=float, format=None):
def random_array(shape, density=0.01, format='coo', dtype=None, rng=None, data_sampler=None):
Die Funktion random_array hat ein shape (2-Tupel) Argument anstelle von zwei ganzen Zahlen. Und das rng Argument hat standardmäßig NumPy's neues default_rng(). Dies unterscheidet sich von den spmatrix rand und random, die standardmäßig die globale RandomState-Instanz verwenden. Wenn Sie sich nicht viel um diese Dinge kümmern, sollte die Standardeinstellung gut funktionieren. Wenn Ihnen die Initialisierung Ihrer Zufallszahlen wichtig ist, sollten Sie diesem Aufruf beim Wechsel der Funktionen wahrscheinlich ein rng=... Schlüsselwortargument hinzufügen. Zusammenfassend lässt sich sagen: Um auf random_array zu migrieren, ändern Sie den Funktionsnamen, konvertieren Sie das shape-Argument in ein einzelnes Tupel-Argument, lassen Sie alle anderen Parameter wie zuvor und überlegen Sie, welche Art von rng=-Argument verwendet werden soll, falls überhaupt.
Die Funktion diags_array verwendet Keyword-only-Regeln für Argumente. Daher müssen Sie offsets= vor die Offsets-Argumente schreiben. Das scheint bei der Migration von der Verwendung von diags mühsam zu sein, aber es hilft, Verwirrung zu vermeiden und erleichtert das Lesen. Ein einzelner Shape-Parameter ersetzt auch hier zwei ganze Zahlen für diese Migration.
Bestehende Funktionen, die sorgfältig migriert werden müssen#
Diese Funktionen geben sparray oder spmatrix zurück, abhängig von den eingegebenen Typen: kron, kronsum, hstack, vstack, block_diag, tril und triu. Ihre Signaturen sind
def kron(A, B, format=None):
def kronsum(A, B, format=None):
def hstack(blocks, format=None, dtype=None):
def vstack(blocks, format=None, dtype=None):
def block_diag(mats, format=None, dtype=None):
def tril(A, k=0, format=None):
def triu(A, k=0, format=None):
Die Verwendung dieser Funktionen sollte überprüft und die Eingaben angepasst werden, um sicherzustellen, dass die Rückgabewerte sparrays sind. Und im Gegenzug sollten die Ausgaben als sparrays behandelt werden. Um sparrays zurückzugeben, muss mindestens eine Eingabe ein sparray sein. Wenn Sie Listen von Listen oder NumPy-Arrays als Eingabe verwenden, sollten Sie eines davon in ein sparse Array konvertieren, um sparse Arrays zu erhalten.
Funktionen, die für die Migration umbenannt wurden#
Funktion
Neue Funktion
Kommentare
eye
eye_array
identity
eye_array
diags
diags_array
Keyword-only-Eingabe
spdiags
dia_array
Shape als 2-Tupel
bmat
block
rand
random_array
Shape als 2-Tupel und default_rng
random
random_array
Shape als 2-Tupel und default_rng
Details: Formänderungen und Reduktionen#
Konstruktion mit 1D-Liste von Werten
csr_array([1, 2, 3]).shape == (3,)1D-Eingabe erzeugt ein 1D-Array.csr_matrix([1, 2, 3]).shape == (1, 3)1D-Eingabe erzeugt eine 2D-Matrix.
Indexierung und Iteration
Die Indexierung von sparray erlaubt 1D-Objekte, die mit
np.newaxisoderNonezu 2D gemacht werden können. Z.B. ergibtA[3, None, :]eine 2D-Zeile. Die Indexierung eines 2D-sparrays mit implizitem (nicht gegebenem) Spaltenindex ergibt ein 1D-Ergebnis, z.B.A[3](Hinweis: Am besten nicht tun - schreiben Sie es stattdessen alsA[3, :]). Wenn Sie ein 2D-Ergebnis benötigen, verwenden Sienp.newaxisoderNonein Ihrem Index, oder fassen Sie den ganzzahligen Index in eine Liste ein, für die Fancy-Indexing 2D ergibt, z.B.A[[3], :].Iteration über sparse Objekte:
next(M)liefert eine sparse 2D-Zeilenmatrix,next(A)liefert ein sparse 1D-Array.
Reduktionsoperationen entlang einer Achse reduzieren die Form
M.min(axis=1)gibt eine 2D-Zeilenmatrix des Minimums entlang der Achse 1 zurück.A.min(axis=1)gibt ein 1Dcoo_arraydes Minimums entlang der Achse 1 zurück. Einige Reduktionen geben dichte Arrays/Matrizen anstelle von sparse zurück.Methode
Ergebnis
sum(axis)
dense
mean(axis)
dense
argmin(axis)
dense
argmax(axis)
dense
min(axis)
sparse
max(axis)
sparse
nanmin(axis)
sparse
nanmax(axis)
sparse
Im Allgemeinen führen 2D sparray-Eingaben zu 1D-Ergebnissen. 2D spmatrix-Eingaben führen zu 2D-Ergebnissen.
Einige Reduktionen geben einen Skalar zurück. Diese sollten sich wie zuvor verhalten und müssen bei der Migration nicht berücksichtigt werden. Z.B.
A.min()
Entfernte Methoden und Attribute#
Die Methoden
get_shape,getrow,getcol,asfptype,getnnz,getHund die Attribute.Aund.Hsind nur für spmatrices vorhanden, nicht für sparrays. Es wird empfohlen, ihre Verwendung durch Alternativen zu ersetzen, bevor Sie mit der Umstellung auf sparray beginnen.Funktion
Alternative
M.get_shape()
A.shape
M.getformat()
A.format
M.asfptype(…)
A.astype(…)
M.getmaxprint()
A.maxprint
M.getnnz()
A.nnz
M.getnnz(axis)
A.count_nonzero(axis)
M.getH()
A.conj().T
M.getrow(i)
A[i, :]
M.getcol(j)
A[:, j]
M.A
A.toarray()
M.H
A.conj().T
Formzuweisung (
M.shape = (2, 6)) ist für sparray nicht erlaubt. Stattdessen sollten SieA.reshapeverwenden.M.getnnz()gibt die Anzahl der gespeicherten Werte zurück – nicht die Anzahl der Nicht-Null-Werte.A.nnztut dasselbe. Um die Anzahl der Nicht-Null-Werte zu erhalten, verwenden SieA.count_nonzero(). Dies ist nichts Neues für die Migration, kann aber verwirrend sein.Um vom
axis-Parameter vonM.getnnz(axis=...)zu migrieren, können SieA.count_nonzero(axis=...)verwenden, aber es ist kein exakter Ersatz, da es Nicht-Null-Werte anstelle von gespeicherten Werten zählt. Der Unterschied ist die Anzahl der explizit gespeicherten Nullwerte. Wenn Sie wirklich die Anzahl der gespeicherten Werte pro Achse wünschen, benötigen Sie einige NumPy-Tools.Der Ansatz mit NumPy-Tools funktioniert für die Formate COO, CSR, CSC, also konvertieren Sie zu einem davon. Für CSR und CSC ist die Hauptachse komprimiert und
np.diff(A.indptr)gibt ein dichtes 1D-Array mit der Anzahl der gespeicherten Werte für jeden Hauptachsenwert zurück (Zeile für CSR und Spalte für CSC). Die Nebenachsen können mitnp.bincount(A.indices, minlength=N)berechnet werden, wobeiNdie Länge der Nebenachse ist (z.B.A.shape[1]für CSR). Die Funktionbincountfunktioniert für jede Achse des COO-Formats unter Verwendung vonA.coords[axis]anstelle vonA.indices.
Tests verwenden, um * und ** Stellen zu finden#
Es kann schwierig sein, skalare Multiplikation
*von Matrixmultiplikation*zu unterscheiden, während Sie Ihren Code migrieren. Python hat dies theoretisch gelöst, indem der Matrixmultiplikationsoperator@eingeführt wurde.*wird für skalare Multiplikation verwendet, während@für Matrixmultiplikation verwendet wird. Aber die Konvertierung von Ausdrücken, die*für beide verwenden, kann knifflig sein und zu Augenermüdung führen. Glücklicherweise, wenn Ihr Code eine Testsuite hat, die die auszudringenden Ausdrücke abdeckt, können Sie sie verwenden, um Stellen zu finden, an denen*für Matrixmultiplikation mit sparse Matrizen verwendet wird. Ändern Sie diese in@.Der Ansatz "monkey-patches" die dunder-Methoden der spmatrix-Klasse, um eine Ausnahme auszulösen, wenn
*für Matrixmultiplikation verwendet wird (und nicht für skalare Multiplikation). Die Testsuite wird an diesen Stellen einen Fehler melden. Und ein Testfehler ist hier ein Erfolg, weil er zeigt, wo Änderungen vorgenommen werden müssen. Ändern Sie das fehlerhafte*in@, suchen Sie in der Nähe nach ähnlichen Änderungen und führen Sie die Tests erneut aus. Ähnlich hilft dieser Ansatz, Stellen zu finden, an denen**für Matrixpotenz verwendet wird. SciPy löst eine Ausnahme aus, wenn@für skalare Multiplikation verwendet wird, so dass dies Stellen erfasst, an denen Sie fälschlicherweise etwas geändert haben. Die Testsuite mit diesem Monkey-Patch prüft also auch die Korrekturen.Fügen Sie den folgenden Code zu Ihrer
conftest.pyDatei hinzu. Führen Sie dann Ihre Tests lokal aus. Wenn es viele Matrixausdrücke gibt, möchten Sie vielleicht einen Abschnitt Ihres Codes nach dem anderen testen. Ein schneller Blick auf den Code zeigt, dass er einenValueErrorauslöst, wann immer*zwischen zwei matrixähnlichen Objekten (sparse oder dense) verwendet wird, und wann immer**für Matrixpotenz verwendet wird. Außerdem gibt er eine Warnung aus, wann immer sum/mean/min/max/argmin/argmax mit einer Achse verwendet werden, so dass die Ausgabe bei spmatrix 2D und bei sparray 1D ist. Das bedeutet, dass Sie überprüfen müssen, ob der Code entweder 1D- oder 2D-Ausgaben überflatten/ravel,np.atleast_2doder Indexierung verarbeiten kann.#================== Added to check spmatrix usage ======================== import scipy from warnings import warn def flag_this_call(*args, **kwds): raise ValueError("Old spmatrix function names for rand/spdiags called") scipy.sparse._construct.rand = flag_this_call scipy.sparse._construct.spdiags = flag_this_call class _strict_mul_mixin: def __mul__(self, other): if not scipy.sparse._sputils.isscalarlike(other): raise ValueError('Operator * used here! Change to @?') return super().__mul__(other) def __rmul__(self, other): if not scipy.sparse._sputils.isscalarlike(other): raise ValueError('Operator * used here! Change to @?') return super().__rmul__(other) def __imul__(self, other): if not scipy.sparse._sputils.isscalarlike(other): raise ValueError('Operator * used here! Change to @?') return super().__imul__(other) def __pow__(self, *args, **kwargs): raise ValueError('spmatrix ** found! Use linalg.matrix_power?') @property def A(self): raise TypeError('spmatrix A property found! Use .toarray()') @property def H(self): raise TypeError('spmatrix H property found! Use .conjugate().T') def asfptype(self): raise TypeError('spmatrix asfptype found! rewrite needed') def get_shape(self): raise TypeError('spmatrix get_shape found! Use .shape') def getformat(self): raise TypeError('spmatrix getformat found! Use .format') def getmaxprint(self): raise TypeError('spmatrix getmaxprint found! Use .shape') def getnnz(self): raise TypeError('spmatrix getnnz found! Use .nnz') def getH(self): raise TypeError('spmatrix getH found! Use .conjugate().T') def getrow(self): raise TypeError('spmatrix getrow found! Use .row') def getcol(self): raise TypeError('spmatrix getcol found! Use .col') def sum(self, *args, **kwds): axis = args[0] if len(args)==1 else args if args else kwds.get("axis", None) if axis is not None: warn(f"\nMIGRATION WARNING: spmatrix sum found using axis={axis}. " "\nsparray with a single axis will produce 1D output. " "\nCheck nearby to ensure 1D output is handled OK in this spot.\n") print(f"{args=} {axis=} {kwds=}") return super().sum(*args, **kwds) def mean(self, *args, **kwds): axis = args[0] if len(args)==1 else args if args else kwds.get("axis", None) if axis is not None: warn(f"\nMIGRATION WARNING: spmatrix mean found using axis={axis}." "\nsparray with a single axis will produce 1D output.\n" "Check nearby to ensure 1D output is handled OK in this spot.\n") return super().mean(*args, **kwds) def min(self, *args, **kwds): axis = args[0] if len(args)==1 else args if args else kwds.get("axis", None) if axis is not None: warn(f"\nMIGRATION WARNING: spmatrix min found using axis={axis}." "\nsparray with a single axis will produce 1D output. " "Check nearby to ensure 1D output is handled OK in this spot.\n") return super().min(*args, **kwds) def max(self, *args, **kwds): axis = args[0] if len(args)==1 else args if args else kwds.get("axis", None) if axis is not None: warn(f"\nMIGRATION WARNING: spmatrix max found using axis={axis}." "\nsparray with a single axis will produce 1D output. " "Check nearby to ensure 1D output is handled OK in this spot.\n") return super().max(*args, **kwds) def argmin(self, *args, **kwds): axis = args[0] if len(args)==1 else args if args else kwds.get("axis", None) if axis is not None: warn(f"\nMIGRATION WARNING: spmatrix argmin found using axis={axis}." "\nsparray with a single axis will produce 1D output. " "Check nearby to ensure 1D output is handled OK in this spot.\n") return super().argmin(*args, **kwds) def argmax(self, *args, **kwds): axis = args[0] if len(args)==1 else args if args else kwds.get("axis", None) if axis is not None: warn(f"\nMIGRATION WARNING: spmatrix argmax found using axis={axis}." "\nsparray with a single axis will produce 1D output. " "Check nearby to ensure 1D output is handled OK in this spot.\n") return super().argmax(*args, **kwds) class coo_matrix_strict(_strict_mul_mixin, scipy.sparse.coo_matrix): pass class bsr_matrix_strict(_strict_mul_mixin, scipy.sparse.bsr_matrix): pass class csr_matrix_strict(_strict_mul_mixin, scipy.sparse.csr_matrix): pass class csc_matrix_strict(_strict_mul_mixin, scipy.sparse.csc_matrix): pass class dok_matrix_strict(_strict_mul_mixin, scipy.sparse.dok_matrix): pass class lil_matrix_strict(_strict_mul_mixin, scipy.sparse.lil_matrix): pass class dia_matrix_strict(_strict_mul_mixin, scipy.sparse.dia_matrix): pass scipy.sparse.coo_matrix = scipy.sparse._coo.coo_matrix = coo_matrix_strict scipy.sparse.bsr_matrix = scipy.sparse._bsr.bsr_matrix = bsr_matrix_strict scipy.sparse.csr_matrix = scipy.sparse._csr.csr_matrix = csr_matrix_strict scipy.sparse.csc_matrix = scipy.sparse._csc.csc_matrix = csc_matrix_strict scipy.sparse.dok_matrix = scipy.sparse._dok.dok_matrix = dok_matrix_strict scipy.sparse.lil_matrix = scipy.sparse._lil.lil_matrix = lil_matrix_strict scipy.sparse.dia_matrix = scipy.sparse._dia.dia_matrix = dia_matrix_strict scipy.sparse._compressed.csr_matrix = csr_matrix_strict scipy.sparse._construct.bsr_matrix = bsr_matrix_strict scipy.sparse._construct.coo_matrix = coo_matrix_strict scipy.sparse._construct.csc_matrix = csc_matrix_strict scipy.sparse._construct.csr_matrix = csr_matrix_strict scipy.sparse._construct.dia_matrix = dia_matrix_strict scipy.sparse._extract.coo_matrix = coo_matrix_strict scipy.sparse._matrix.bsr_matrix = bsr_matrix_strict scipy.sparse._matrix.coo_matrix = coo_matrix_strict scipy.sparse._matrix.csc_matrix = csc_matrix_strict scipy.sparse._matrix.csr_matrix = csr_matrix_strict scipy.sparse._matrix.dia_matrix = dia_matrix_strict scipy.sparse._matrix.dok_matrix = dok_matrix_strict scipy.sparse._matrix.lil_matrix = lil_matrix_strict del coo_matrix_strict del bsr_matrix_strict del csr_matrix_strict del csc_matrix_strict del dok_matrix_strict del lil_matrix_strict del dia_matrix_strict #==========================================
Index-Array-Dtypes#
Wenn Sie komprimierte Indizes an einen Konstruktor übergeben, z.B. csr_array((data, indices, indptr)), setzt sparse Arrays den Index-dtype, indem es nur den dtype der Index-Arrays prüft. Sparse Matrizen prüfen auch die Indexwerte und können zu int32 herunterskaliert werden (weitere Details siehe gh-18509). Das bedeutet, Sie können int64-Indizierung erhalten, wo Sie früher int32 hatten. Sie können dies steuern, indem Sie den dtype vor der Instanziierung festlegen oder nach der Konstruktion neu casten.
Zwei sparse Hilfsfunktionen können bei der Handhabung des Index-dtypes helfen. Verwenden Sie get_index_dtype(arrays, maxval, check_contents) während der Erstellung von Indizes, um einen geeigneten dtype (int32 oder int64) für Ihre komprimierten Indizes zu finden.
Verwenden Sie safely_cast_index_arrays(A, idx_dtype) zum Neucasten nach der Konstruktion, wobei Sie sicherstellen, dass Sie keine Überläufe beim Herunterskalieren erzeugen. Diese Funktion ändert das Eingabearray nicht tatsächlich. Die gecasteten Arrays werden zurückgegeben. Und Kopien werden nur bei Bedarf erstellt. Sie können also prüfen, ob ein Casting durchgeführt wurde, mit if indices is not A.indices:
Die Funktion Signaturen sind
def get_index_dtype(arrays=(), maxval=None, check_contents=False):
def safely_cast_index_arrays(A, idx_dtype=np.int32, msg=""):
Beispiel-Idiome umfassen die folgenden für get_index_dtype
.. code-block:: python
# select index dtype before construction based on shape
shape = (3, 3)
idx_dtype = scipy.sparse.get_index_dtype(maxval=max(shape))
indices = np.array([0, 1, 0], dtype=idx_dtype)
indptr = np.arange(3, dtype=idx_dtype)
A = csr_array((data, indices, indptr), shape=shape)
und für safely_cast_index_arrays
.. code-block:: python
# rescast after construction, raising exception if shape too big
indices, indptr = scipy.sparse.safely_cast_index_arrays(B, np.int32)
B.indices, B.indptr = indices, indptr
Sonstiges#
Binäre Operatoren
+, -, *, /, @, !=, >wirken auf sparse und/oder dichte OperandenWenn alle Eingaben sparse sind, ist die Ausgabe normalerweise auch sparse. Die Ausnahme ist
/, das dense zurückgibt (Division durch den Standardwert0istnan).Wenn Eingaben gemischt sparse und dense sind, ist das Ergebnis normalerweise dense (d.h.
np.ndarray). Ausnahmen sind*, das sparse ist, und/, das fürdense / sparsenicht implementiert ist und sparse fürsparse / densezurückgibt.
Binäre Operatoren
+, -, *, /, @, !=, >mit Array- und/oder Matrix-OperandenWenn alle Eingaben Arrays sind, sind die Ausgaben Arrays, und dasselbe gilt für Matrizen.
Beim Mischen von sparse Arrays mit sparse Matrizen gibt der führende Operand den Typ für die Ausgabe an, z.B.
sparray + spmatrixergibt ein sparse Array, während die Umkehrung der Reihenfolge ein sparse Matrix ergibt.Beim Mischen von dense Matrizen mit sparse Arrays sind die Ergebnisse normalerweise Arrays mit Ausnahmen für Vergleiche, z.B.
>, das dense Matrizen zurückgibt.Beim Mischen von dense Arrays mit sparse Matrizen sind die Ergebnisse normalerweise Matrizen mit einer Ausnahme für
array @ sparse matrix, die ein dense Array zurückgibt.