26

If I have z = cumsum( [ 0, 1, 2, 6, 9 ] ), which gives me z = [ 0, 1, 3, 9, 18 ], how can I get back to the original array [ 0, 1, 2, 6, 9 ] ?

Mazdak
  • 105,000
  • 18
  • 159
  • 188
scottlittle
  • 18,866
  • 8
  • 51
  • 70

5 Answers5

42
z[1:] -= z[:-1].copy()

Short and sweet, with no slow Python loops. We take views of all but the first element (z[1:]) and all but the last (z[:-1]), and subtract elementwise. The copy makes sure we subtract the original element values instead of the values we're computing. (On NumPy 1.13 and up, you can skip the copy call.)

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • I don't think this works, I'm getting this error message: AttributeError: 'list' object has no attribute 'copy' – Pedro Jul 29 '16 at 20:31
  • @Pedro: That's because you're using a list instead of an array. Despite the question's notation, `np.cumsum` returns an array. – user2357112 Jul 29 '16 at 20:32
  • Thanks, your answer is brilliant! I imagine this is what is going on behind the scenes for np.diff. If not, maybe it should be. – scottlittle Jul 29 '16 at 21:54
  • As a person not very familiar with Python syntax, I'm a bit lost as to what's going on here. I'd love to see an explanation in the question! :) – Jeff B Aug 24 '16 at 22:21
  • 1
    @JeffBridgman: It's a very NumPy-specific way of doing things, so general Python syntax knowledge wouldn't help much. Particularly, if you tried this with `z = [ 0, 1, 3, 9, 18 ]` like the question says, you'd just get an `AttributeError`, since `z` really has to be a NumPy array instead of a list. (`np.cumsum` gives an array, so for the purposes of inverting `np.cumsum`, this code works fine.) I'd recommend checking out the [NumPy tutorial](https://docs.scipy.org/doc/numpy-dev/user/quickstart.html), particularly the "Basic Operations" and "Indexing, Slicing and Iterating" sections. – user2357112 Aug 26 '16 at 04:49
13

The following preserves the first element, too:

np.diff(z, prepend=0)
BlackHC
  • 592
  • 5
  • 10
10

You can use np.diff to compute elements 1...N which will take the difference between any two elements. This is the opposite of cumsum. The only difference is that diff will not return the first element, but the first element is the same in the original and cumsum output so we just re-use that value.

orig = np.insert(np.diff(z), 0, z[0])

Rather than insert, you could also use np.concatenate

orig = np.concatenate((np.array(z[0]).reshape(1,), np.diff(z)))

We could also just copy and replace elements 1...N

orig = z.copy()
orig[1:] = np.diff(z)
Suever
  • 64,497
  • 14
  • 82
  • 101
5

If you want to keep z, you can use np.ediff1d:

x = np.ediff1d(z, to_begin=z[0])
kuppern87
  • 1,125
  • 9
  • 14
3

My favorite:

orig = np.r_[z[0], np.diff(z)]
stmax
  • 6,506
  • 4
  • 28
  • 45