1

Here is mentioned that appending to numpy array is not an good idea because it requires re-allocation of the array memory and it slows down the code. There are also mentioned some hints how to avoid it. My goal is to create an saw signal, something like this ASCII art: /\/\/\/\. I've end up with following two codes and I do not know which one is worse. 2nd one uses also itertools.islice which is also not world's speed recorder as it discussed here. Both codes mixes standard python lists and numpy arrays. Is there a way how can achieve the same but using pure numpy arrays? Or better: is there any general rule which I can use with numpy everywhere where I would use list.append instead? As I said on 1st page are mentioned some hints but I cannot figure out working solution. I've been thinking about something like list comprehension that will allow me expand the saw array first which then I could pass to np.hstack but I do not think this is possible. I've been also thinking about first declaring numpy array with numpy.empty(400) or np.zeros(400) but I do not know how to properly assign to them further values and seems that np.empty is not so completely empty because it contains zero values:

In [106]: x = np.zeros(10)
In [107]: x
Out[107]: array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])

In [108]: y = np.empty(10)
In [109]: y
Out[109]: array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])

1st

import numpy as np
import matplotlib.pyplot as plt

saw = []
for x in xrange(0, 3):
  saw.append(np.hstack((np.linspace(0,1,50), np.linspace(1,0,50))))
saw2 = saw[0]
for x in saw:
  saw2 = np.append([saw2], [x])
plt.figure()
plt.plot(np.arange(saw2.size), saw2)
plt.show()

2nd

import numpy as np
from itertools import islice
import matplotlib.pyplot as plt

saw = []
for x in xrange(0, 4):
  saw.append(np.hstack((np.linspace(0,1,50), np.linspace(1,0,50))))
saw2 = saw[0]
for x in islice(saw, 1, None, 1):
  saw2 = np.append([saw2], [x])
plt.figure()
plt.plot(np.arange(saw2.size), saw2)
plt.show()
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Wakan Tanka
  • 7,542
  • 16
  • 69
  • 122
  • 1
    You might try doing some performance testing to find out what is really most efficient. Some things worth testing are insert at the beginning vs at the end vs append vs contatenate. Some results are at http://stackoverflow.com/questions/7133885/fastest-way-to-grow-a-numpy-numeric-array. –  Jul 30 '15 at 13:09
  • 2
    Generally - work out the size of your array first. Then allocate an array of this size with, say, `np.zeros` or `np.empty`. Then assign the results to the appropriate slice of the array, e.g. `saw[start_index:end_index] = ...` – YXD Jul 30 '15 at 13:21
  • Thanks for tips guys – Wakan Tanka Jul 31 '15 at 20:56

1 Answers1

1

Your 2 iterations are only of size 3. That's to construct an array that is (400,). That kind of iteration isn't something to worry about much.

I can clean up your code by writing it as:

xup=np.linspace(0,1,50)
xdn=np.linspace(1,0,50)
x=np.hstack([xup,xdn])
saw2 = np.hstack([x for _ in range(4)])

The list comprehension is just your saw.

np.stack (or np.concatenate) takes a list (or lists or arrays), so there's no need to iterate through the list, doing a concatenate item by item. np.append is just a pairwise concatenate:

 np.append(saw2,x) == np.concatenate([saw2,x])

It's even simpler to use np.tile to replicate x

saw2 = np.tile(x,4)

or something a bit faster (tile uses repeat in a similar way)

saw2 = x[None,:].repeat(4,0).flatten()
hpaulj
  • 221,503
  • 14
  • 230
  • 353