5
$\begingroup$

I have a huge array of positive and negative numbers. I am trying to find cumulative sum of consecutive positive and negative numbers. The cumulative sum should restart every time the sign changes.

For example, I have

data = 
  {-1, 2, 3, 4, 2, 1, -2, -5, 3, 1, 2, 1, -1, -1, 1, 2, 4, -1, 1, 1, -1, -2, 1};

I want:

cusum = 
  {-1, 2, 5, 9, 11, 12, -2, -7, 3, 4, 6, 7, -1, -2, 1, 3, 7, -1, 1, 2, -1, -3, 1};

so that the result looks like

enter image description here

Any help is greatly appreciated.

$\endgroup$
9
$\begingroup$

With data being

data = {-1, 2, 3, 4, 2, 1, -2, -5, 3, 1, 2, 1, -1, -1, 1, 2, 4, -1, 1, 1, -1, -2, 1};

as in the OP, then do

Accumulate /@ SplitBy[data, Sign] // Flatten
(* {-1, 2, 5, 9, 11, 12, -2, -7, 3, 4, 6, 7, -1, -2, 1, 3, 7, -1, 1, 2, -1, -3, 1} *)
| improve this answer | |
$\endgroup$
  • $\begingroup$ @ march, thank you so much. In fact, I spent almost an hour to do it without success. I am going to leave this question so that someone in the future will not waste their time. I really appreciate it. $\endgroup$ – ramesh Aug 9 '17 at 5:37
7
$\begingroup$

Since you mentioned you are working with huge arrays, you might consider using Compile. For instance, here are two possible Compile approaches:

fc = Compile[{{a, _Integer}, {b, _Integer}},
    If[a b <= 0, b, a + b]
];

gc = Compile[{{a, _Integer, 1}},
    Module[{total = 0},
        Table[
            If[a[[i]] total <= 0,
                total = a[[i]],
                total += a[[i]]
            ],
            {i, Length[a]}
        ]
    ]
];

A comparison on a list with a million elements:

data = RandomInteger[{-5, 5}, 10^6];

r1 = gc[data]; //AbsoluteTiming
r2 = FoldList[fc, data]; //AbsoluteTiming
r3 = Accumulate /@ SplitBy[data, Sign] // Flatten; //AbsoluteTiming

r1 === r2 === r3

{0.047799, Null}

{0.072444, Null}

{1.45911, Null}

True

| improve this answer | |
$\endgroup$
  • $\begingroup$ @ Carl, thank you for your time and answer. It is really appreciated. $\endgroup$ – ramesh Aug 9 '17 at 13:16
4
$\begingroup$
Flatten[FoldList[Plus, #] & /@ Split[data, Sign[#1] == Sign[#2] &],2]
| improve this answer | |
$\endgroup$
  • $\begingroup$ @ Alucard, thank you for your time and answer. I really appreciate it. $\endgroup$ – ramesh Aug 9 '17 at 13:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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