Efficiently extracting a column of a sparse matrix

Given a sparse matrix S, how can I efficiently extract the ith column of S? I know I can use @view S.nzval[S.colptr[i] : S.colptr[i + 1] - 1] but it’s a bit clunky.

Note that what you wrote only extracts the structural nonzeros of the column, not the full column. You also need to attach the row indices and rewrap in a sparse vector. But I’ll assume you knew that and simply misspoke.

There is an efficient method for getting a copy (not view) of a column simply via S[:,col] (see @less S[:,1]). It does contain the code you wrote as part of it. You could create a version of the builtin that uses @view. Be warned that any mutation of the nonzero structure may cause it to diverge from or corrupt the original.

It may be that a specialized view type is deliberately unsupported due to this fragility. But I’ll remark that SparseMatrixCSC (the standard sparse array type) supports O(1) random access to columns, so the generic @view is probably mostly okay. They even specialize a couple of methods (*, nnz, and nonzeros) on column views of AbstractSparseMatrixCSC (via the SparseArrays.SparseColumnView alias), but maybe not all the methods you would hope for.

So the answer to your question is “the most efficient way is what you’re proposing (with the bug fixed, like S[:,1])”. But I would see whether a standard column view (or non-view) comes close in performance and prefer that if it’s close, to outsource that headache.

2 Likes

Sorry, I meant to write “compressed column” instead of column.

The following should be efficient:

julia> using SparseArrays

julia> M = sprand(5,5,0.3)
5×5 SparseMatrixCSC{Float64, Int64} with 5 stored entries:
  ⋅   0.701338   ⋅        ⋅    ⋅ 
  ⋅    ⋅         ⋅        ⋅   0.804534
  ⋅   0.700287   ⋅        ⋅   0.131449
  ⋅    ⋅        0.15562   ⋅    ⋅ 
  ⋅    ⋅         ⋅        ⋅    ⋅ 

julia> v = @view M[:,2]
5-element view(::SparseMatrixCSC{Float64, Int64}, :, 2) with eltype Float64:
 0.7013376258268622
 0.0
 0.7002872223003926
 0.0
 0.0

julia> nonzeros(v)
2-element view(::Vector{Float64}, 1:2) with eltype Float64:
 0.7013376258268622
 0.7002872223003926
1 Like