1

I need to perform a cumulative sum with bounds - kind of like the charge state of a capacitor. It can't go above its maximum charge, and can't go below 0. Something like:

Initial  Cumulative Sum Constrained Sum
 1        1               1
 7        8               8
 5        13              10
 -8       5               2
 -7       -2              0
 3        1               3

I have a piece of code:

charge_0 = 0
for i in range (1, len(charge_discharge)):
    charge_1 = min(battery_size,max(0,(charge_0+charge_discharge[i])))
    StorageSOC.append(charge_1)
    charge_0 = charge_1

It works faster than some other options, but I know it is not optimized. A simple cumulative sum is orders of magnitude faster, so I am sure there is a better way to do this. I can't just apply a clip at the bounds. What is the right way to do this without the for loop?

chadb
  • 51
  • 5
  • What is your data structure? Is it a list-of-lists, or is it something more suited to doing fast parallel data operations like a pandas dataframe – Pranav Hosangadi Apr 08 '21 at 19:03
  • 2
    Because clipping element N affects all the sums thereafter. – Tim Roberts Apr 08 '21 at 19:03
  • Related: https://stackoverflow.com/questions/32890124/pandas-dataframe-running-sum-with-reset/32891081#32891081 – Pranav Hosangadi Apr 08 '21 at 19:07
  • Pranav: Right now I have the data as a list since I am looping and looking up indices in an array slows the process. However, I'm not tied to any particular format. The question is related to the post you mentioned, and I saw that when searching earlier. However, that involves a reset that can be accomplished via groupby. I don't think this can use groupby (unless I'm missing something). – chadb Apr 08 '21 at 20:01

2 Answers2

1

You don't need both old and new. And you're skipping element 0. This is a tiny bit faster, but I don't believe you can eliminate the loop.

charge = 0
for delta in charge_discharge:
    charge = min(battery_size,max(0,charge+delta))
    StorageSOC.append(charge)
Tim Roberts
  • 48,973
  • 4
  • 21
  • 30
  • Thank you, I'll make that change. However, I think there has got to be a solution using something like itertools. I just can't figure out what it would look like. – chadb Apr 08 '21 at 19:25
  • `itertools` is just syntax sugar for a `for` loop. You might be able to write it more compactly, but it will execute in the same time. – Tim Roberts Apr 08 '21 at 19:35
  • As I implemented the solution I realized your improvement comes from you correctly removing the indexing I had left in. I inherited the code and had removed most of those issues, I missed that one though. – chadb Apr 08 '21 at 20:32
0

In the example, j0 and j1 are not defined. no cumsum involved in this piece, please refer a mwe for the correct use of a question

This can be faster using vectorial approach on numpy or pandas, both have cumsum operation.

Glauco
  • 1,385
  • 2
  • 10
  • 20
  • Thank you for noting the j0 and j1. I haven't posted many questions here, those were placeholders in the original code and I didn't fix that in the post. I have corrected that error in my post. However, cumsum does not do what I want it to do. The cumsum performs a cumulative sum, I need the sum to be clipped. What I was looking for is a vectoral approach that allows clipping. – chadb Apr 09 '21 at 14:05
  • Can this https://stackoverflow.com/questions/58518211/cumulative-sum-in-numpy-array-with-condition-for-stop help you? – Glauco Apr 09 '21 at 15:31