Written and maintained by CASRAI Editorial Board
Last updated
SciPy’s scipy.sparse package stores matrices in which most entries are zero by keeping only the non-zero values and their positions. The current documentation says SciPy sparse “is shifting from a sparse matrix interface to a sparse array interface” and that the project expects “to deprecate the sparse matrix interface” in the next few releases, so new code should use classes such as csr_array rather than csr_matrix. This guide builds one array three ways, shows how to read its internal arrays, and maps each storage format and solver to the condition the documentation attaches to it.
What it is used for in research
Sparse storage suits data where each row touches only a few columns: a document-by-term count table, a graph adjacency matrix, or the coefficient matrix of a discretised physical model. Instead of holding every zero, a sparse array holds the non-zero entries only, and scipy.sparse.linalg offers solvers and decompositions that work on that representation. A dense NumPy array remains the better choice when most entries are non-zero; see the NumPy matrix multiplication guide and the numpy.linalg.norm guide for the dense counterparts. Sparse matrices also appear in machine-learning pipelines, for example when text features are passed to a model, as in the train/test split guide.
Install or access
The SciPy project’s install page (scipy.org/install, checked 2026-10-29) gives python -m pip install scipy, after first creating a virtual environment. For conda users it names Miniforge as the recommended way to install conda and mamba, followed by conda install scipy (conda-forge) or mamba install scipy. Sparse support ships inside SciPy; there is nothing separate to install.
Step-by-step: build, convert and solve
1. Build in COO format
The SciPy sparse reference says COO “is recommended” for construction, and that duplicate (i, j) entries are summed when converting to CSR or CSC. Indices do not need to be sorted.
import numpy as np
from scipy import sparse
row = [0, 0, 1, 2, 2, 2]
col = [0, 2, 2, 0, 1, 2]
data = [1, 2, 3, 4, 5, 6]
A = sparse.coo_array((data, (row, col)), shape=(3, 3))
2. Convert to CSR for arithmetic
The reference states that conversions among CSR, CSC and COO “are efficient, linear-time operations”, and that CSR is “especially suitable for fast matrix vector products”.
S = A.tocsr() # or build directly: sparse.csr_array((data, (row, col)), shape=(3, 3))
y = S @ np.array([1, 1, 1])
3. Solve a sparse linear system
scipy.sparse.linalg.spsolve solves Ax = b, where b may be a vector or a matrix.
from scipy.sparse.linalg import spsolve
M = sparse.csr_array(([4, 1, 1, 3], ([0, 0, 1, 1], [0, 1, 0, 1])), shape=(2, 2))
x = spsolve(M, np.array([1, 2]))
Output and how to read it
Call .toarray() to see a sparse array as a dense NumPy array. For the example above, S.toarray() returns [[1,0,2],[0,0,3],[4,5,6]], matching the worked example in the csr_array reference. The same array can be written in CSR’s own layout: indptr = [0, 2, 3, 6] and indices = [0, 2, 2, 0, 1, 2], because “column indices for row i are stored in indices[indptr[i]:indptr[i+1]]“. Row 0 therefore owns indices[0:2] = columns 0 and 2, row 1 owns indices[2:3] = column 2, and row 2 owns indices[3:6] = columns 0, 1 and 2. Here S @ [1, 1, 1] gives the row sums [3, 3, 15], and spsolve(M, [1, 2]) returns approximately [0.0909, 0.6364], which is 1/11 and 7/11: check that 4(1/11) + 7/11 = 1 and 1/11 + 3(7/11) = 2.
Duplicates are summed, not overwritten. With row=[0,1,2,0], col=[0,1,1,0] and data=[1,2,4,8], the two entries at (0, 0) combine into 9, and the result is [[9,0,0],[0,2,0],[0,4,0]].
Which format to use
The table below restates the format notes in the SciPy documentation.
| Format | Class | What the documentation says |
|---|---|---|
| COO | coo_array |
“A sparse array in COOrdinate format”; recommended for construction. |
| CSR | csr_array |
Efficient CSR + CSR and CSR * CSR arithmetic, efficient row slicing, fast matrix-vector products. Column slicing is slow (consider CSC); changes to the sparsity structure are expensive (consider LIL or DOK). |
| CSC | csc_array |
“Compressed Sparse Column array”; the suggested alternative to CSR when column slicing matters. |
| LIL | lil_array |
“Row-based LIst of Lists sparse array”; suggested when the sparsity structure changes. |
| DOK | dok_array |
“Dictionary Of Keys based sparse array”; suggested when the sparsity structure changes. |
| DIA | dia_array |
“Sparse array with DIAgonal storage.” |
| BSR | bsr_array |
“Block Sparse Row format sparse array.” |
Solvers and decompositions in scipy.sparse.linalg
| Function | Documented purpose |
|---|---|
spsolve |
Solve the sparse linear system Ax = b; b may be a vector or a matrix. |
splu |
LU decomposition of a sparse, square matrix. |
cg |
Conjugate Gradient method for Ax = b, for a symmetric, positive-definite A. |
gmres |
Generalized Minimal RESidual method for Ax = b. |
eigs |
k eigenvalues and eigenvectors of a square matrix. |
eigsh |
The eigenvalue routine for real symmetric or complex Hermitian matrices. |
svds |
Partial singular value decomposition of a sparse matrix. |
norm |
Norm of a sparse matrix. |
The only condition the documentation places on cg is symmetric, positive-definite A, so check that property of your matrix before choosing it over gmres.
Troubleshooting
Column slicing is slow
CSR makes row slicing efficient and column slicing slow. If your workload slices columns, convert with .tocsc(); the conversion is linear-time.
Changing the structure of a CSR array is slow
The csr_array reference lists structural changes as expensive and points to LIL or DOK. Build or edit in one of those, then convert to CSR for arithmetic.
Entries are larger than expected
Duplicate (i, j) entries are summed when converting to CSR or CSC. If your input repeats coordinates, the result adds them, as in the 9 example above.
Code uses csr_matrix
The matrix interface is the one the documentation expects to deprecate. Moving to the array classes (csr_array, coo_array) is the forward-compatible choice. Related SciPy topics: scipy.optimize, scipy.interpolate and scipy.signal.
Free alternatives
| Option | What its documentation says |
|---|---|
| NumPy dense arrays | The standard dense array that .toarray() returns; store every entry, zeros included. |
pydata sparse package |
Implements sparse arrays of arbitrary dimension on top of numpy and scipy.sparse. sparse.COO and sparse.DOK generalize the scipy.sparse COO and DOK layouts, and sparse.GCXS extends compressed sparse storage beyond two dimensions (sparse.pydata.org, checked 2026-10-29). |
FAQ
What does scipy.sparse do?
It provides sparse array classes in seven formats and a sparse.linalg module of solvers and decompositions that operate on them.
Should I use csr_array or csr_matrix?
Use csr_array. The SciPy documentation says the project is shifting to the array interface and expects to deprecate the matrix interface.
Which format should I build a sparse array in?
COO, which the documentation recommends for construction, then convert to CSR or CSC for arithmetic.
How do I convert a sparse array to a dense one?
Call .toarray().
Sources
- SciPy documentation: Sparse arrays (scipy.sparse), checked 2026-10-29.
- SciPy documentation: scipy.sparse.csr_array, checked 2026-10-29.
- SciPy documentation: Sparse linear algebra (scipy.sparse.linalg), checked 2026-10-29.
- SciPy: Install, checked 2026-10-29.
- PyData sparse documentation, checked 2026-10-29.







