11
$\begingroup$

Consider the 'm' matrix: Link to 'matrix.dat': https://drive.google.com/drive/folders/1COdMCCBKq85vMDj6Jrb2qqoUlE9eTk6w?usp=sharing

m = Import["matrix.dat"];

enter image description here Let's define 'area accumulation' for matrices as follows:

m1=Accumulate[Accumulate /@ m];

enter image description here

How to add a condition so that the cumulative is only for elements other than zero? (so that the zero elements remain zeros)? It would be good if the code was fast because I will do it for many matrices :)

$\endgroup$
2
  • $\begingroup$ Q: something like picking the non-zero entries and then Accumulate over those? Something like Accumulate[SparseArray[m]["NonzeroValues"]] or did I misunderstand? $\endgroup$
    – user49048
    Commented Mar 8, 2022 at 19:46
  • 1
    $\begingroup$ Please provide a programmatic way to access your data. People should not need to fill out forms or sign up for services to reproduce your code. See this Q&A about how to Upload large amounts of data more easily in Mathematica Meta. $\endgroup$
    – rhermans
    Commented Aug 9, 2023 at 12:22

2 Answers 2

11
$\begingroup$

If the input matrix sa is numeric, you can multiply the accumulated versions with Unitize[sa]. For example,

SeedRandom[1]
sa = SparseArray @ RandomChoice[{3, 1, 1, 1} -> {0, 1, 2, 3}, {7, 7}]

enter image description here

MatrixForm[sa]

enter image description here

sa0 = Unitize[sa] (Accumulate /@ sa);


MatrixForm[sa0]

enter image description here

sa1 = Unitize[sa] Accumulate[sa0];

MatrixForm[sa1]

enter image description here

If the input matrix may have non-numeric elements use saUnitize instead of Unitize where

ClearAll[saUnitize]
saUnitize = SparseArray[#["NonzeroPositions"] -> 1, Dimensions @ #] &;

Example:

SeedRandom[1]

sb = SparseArray @ RandomChoice[{3, 1, 1, 1} -> {0, a, b, 3}, {7, 7}];

MatrixForm[sb]

enter image description here

sb0 = saUnitize[sb] (Accumulate /@ sb);

MatrixForm[sb0]

enter image description here

sb1 = saUnitize[sb] Accumulate[sb0];

MatrixForm[sb1]

enter image description here

Update:

Combining the steps into a single function:

ClearAll[accumulateNonzeroValues]

accumulateNonzeroValues = (saUnitize[sa] # &) @* Accumulate @* 
 (saUnitize[sa] # &) @* Map[Accumulate];


accumulateNonzeroValues @ sa == sa1
True
accumulateNonzeroValues @ sb == sb1
True

Alternatively, you can also use a combination of SubsetMap + Fold + Accumulate as follows:

foldAccumulate[s_SparseArray] := 
    Module[{pos = Join @@ (GatherBy[s["NonzeroPositions"], #] & /@ {First, Last})}, 
      Fold[SubsetMap[Accumulate, #, #2] &, s,  pos]];


foldAccumulate @ sa == sa1
 True
foldAccumulate @ sb == sb1
 True 
$\endgroup$
0
$\begingroup$

If we want to skip String, Symbols and missing values:

SeedRandom[1];
dt = SparseArray @ RandomChoice[{3, 1, 1, 1} -> {1, "a", Missing[_], 3}, {7, 7}] // Normal;

skip[v_?VectorQ] :=
 Module[{as, st, nm},
  as = AssociationThread[Range @ Length[v] -> v];
  st = Select[as, MatchQ[_String | _Symbol | _Missing]];
  nm = Select[as, NumberQ];
  <|Thread[Keys[nm] -> Accumulate @ Values[nm]], st|> // KeySort // Values]

Strangely, Accumulate doesn't know Associations (other functions like MovingAverage do).

Block[{set = Dataset[#, ItemSize -> 4] &},
 Row[{dt // set, " \[DoubleLongRightArrow] ", skip /@ dt // set}]]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.