# Replace values in sparse matrix

I am interested in updating the values of the sparse matrix. I have a list of matrix element which I am interested in updating and a list of new values. Currently, I do it in the following manner:

s = SparseArray[{{i_, i_} -> i}, {100, 100}];
newP = RandomInteger[{1, 100}, {5, 2}];
newV = RandomReal[1, {5}];
MapThread[(s[[#1[[1]], #1[[2]]]] = #2) &, {newP, newV}]


Any suggestions on how to do it more efficiently?

• In you actual use case: Are the new positions among the nonzero positions of the old array? Commented Aug 1, 2018 at 9:15
• No, I am updating sub-set of nonzero values of the matrix Commented Aug 1, 2018 at 9:21
• Module[{nzp = Join[newP, s["NonzeroPositions"]], nzv = Join[newV, s["NonzeroValues"]]}, SparseArray[nzp->nzv, Dimensions[s]]] seems to be faster.
– kglr
Commented Aug 1, 2018 at 9:23
• Related, but not duplicate: (777) – that question deals with element-by-element updates, whereas this question permits bulk replacement. Commented Aug 1, 2018 at 10:27

s = SparseArray[{{i_, i_} -> i}, {10000, 10000}];

newP = RandomInteger[{1, 10000}, {4000, 2}];
newV = RandomReal[1, {4000}];

s1 = s;
MapThread[(s1[[#1[[1]], #1[[2]]]] = #2) &, {newP, newV}] //
RepeatedTiming // First


1.93

(s2 = With[{nzp = Join[newP, s["NonzeroPositions"]],
nzv = Join[newV, s["NonzeroValues"]]},
SparseArray[nzp -> nzv, Dimensions[s]]]) //
RepeatedTiming  // First


0.0019

(s4 = With[{mask = SparseArray[newP -> 1, Dimensions[s]],
ns = SparseArray[newP -> newV, Dimensions[s]]}, (1 - mask) s +
mask ns]) // RepeatedTiming // First


0.0012

s1 == s2 == s4


True

Versus Mr.Wizard's method:

RepeatedTiming[
s3 = s +  SparseArray[newP -> newV - Extract[s, newP], Dimensions[s]];
] // First


0.0016

• Interesting; s4 is significantly slower than the others on my system, timing 0.00270. A variation of that was the first thing I tried. Commented Aug 1, 2018 at 11:17
• @Mr.Wizard, please note that i had changed 5000 to 4000 to avoid memory limits of free cloud plan. The timings i posted are obtained in Wolfram Cloud (v11.3).
– kglr
Commented Aug 1, 2018 at 11:35
• @Mr.Wizard, in version 9 s4 is slower than both s2 and s3.
– kglr
Commented Aug 1, 2018 at 11:42

Compared to kglr's answer this is marginally faster on my system (version 10.1), and a little simpler. It may be acceptable in many cases, however it will not work if you are trying to update Real to Integer values for example, because by way of numeric operations the Integers will be cast to Real.

s + SparseArray[newP -> newV - Extract[s, newP], Dimensions[s]]


Timings:

(* example code from kglr's answer *)

s = SparseArray[{{i_, i_} -> i}, {10000, 10000}];
newP = RandomInteger[{1, 10000}, {5000, 2}];
newV = RandomReal[1, {5000}];

(* his method again for comparative timing *)

(s2 =
Module[{nzp = Join[newP, s["NonzeroPositions"]],
nzv = Join[newV, s["NonzeroValues"]]},
SparseArray[nzp -> nzv, Dimensions[s]]]) // RepeatedTiming // First

(* my method *)

RepeatedTiming[
s3 = s + SparseArray[newP -> newV - Extract[s, newP], Dimensions[s]];
] // First

(* confirm equivalence *)

s2 == s3

0.00162

0.00145

True