Appending to array or looping iterable from fixed array

Question:

I have been using this method for Ranges. I can’t work out an equivalent method for fixed lists/arrays.

# What I've been using & OUTPUT I'm looking for.

degrees = np.arange(10,50,10)
ITER = np.array(degrees)
for i in range( 4): 
    x1 = np.sin(np.radians(ITER))
    y1 = np.cos(np.radians(ITER ))
XY = np.column_stack((np.asarray(x1),np.asarray(y1)))
print(XY)

Bad code:

# appending to array has seen many failures.  
# appended array always prints empty. must have a false assumption
xy1 = np.array([])
degrees = np.array([10, 20, 30, 40])
for degree in np.nditer(degrees):
    x1 = np.sin(np.radians(degree))
    y1 = np.cos(np.radians(degree))
    #np.append(xy1,[x1,y1]).reshape(2,1)
    #ugh = np.asarray([x1,y1])
    #a = np.append(xy1,[[x1,y1]],axis =0).reshape(2,-1)
    #a = np.append(xy1,[[x1],[y1]],axis =0)#.reshape(2,-1)
    #np.append(xy1,ugh, axis =0).reshape(2,1)
    #np.append(xy1,ugh, axis =0)
    #a = np.append(xy1,[ugh])
XY = np.column_stack((np.asarray(x1),np.asarray(y1)))
print(xy1)

# OUTPUT should be same as working example above

With the benefit of hindsight I would have used lists… But now I wish to use this as learning opportunity.

Update: Answers as provided by @hpaulj

# Iterate through Range
degrees = np.arange(10,50,10)
x1 = np.sin(np.radians(degrees))
y1 = np.cos(np.radians(degrees ))
XY = np.column_stack((x1, y1))

# Iterate through fixed list
degrees = np.array([10, 20, 30, 40])
XY = np.zeros((0,2))
for rad in np.radians(degrees):
    XY = np.append(XY, [[np.sin(rad), np.cos(rad)]], axis=0)

My main mistake was the initialization of the array as wrong shape.

XY = np.zeros((0,2))
degrees = np.array([10, 20, 30, 40])
for rads in np.radians(degrees):
    x1 = np.sin(rads)
    y1 = np.cos(rads)
    XY = np.append(XY, [[x1,y1]]).reshape(-1,2)
Asked By: user014162314

||

Answers:

Your first code runs; why are you trying to write something else?

But I think you need to understand the first one better. Let’s run it:

In [449]: degrees = np.arange(10,50,10)
     ...: ITER = np.array(degrees)
     ...: for i in range( 4): 
     ...:     x1 = np.sin(np.radians(ITER))
     ...:     y1 = np.cos(np.radians(ITER ))
     ...: XY = np.column_stack((np.asarray(x1),np.asarray(y1)))

In [450]: degrees
Out[450]: array([10, 20, 30, 40])

In [451]: ITER
Out[451]: array([10, 20, 30, 40])

arange produces an array (READ THE DOCS); so why the extra np.array(degrees) call? It doesn’t change any; it just makes a another copy.

In [452]: XY
Out[452]: 
array([[0.17364818, 0.98480775],
       [0.34202014, 0.93969262],
       [0.5       , 0.8660254 ],
       [0.64278761, 0.76604444]])

degrees is (4,) shape; x1 is as well, and XY is (4,2), concatenating two 1d arrays as columns.

Why the iteration for range(4)? Just to make the code run slower by repeating the sin calculations? You do the same thing 4 times, and don’t accumulate anything. It just uses the last run to make XY. And x1 is already an array; why the extra np.array(x1) wrapping?

In [453]: x1,y1
Out[453]: 
(array([0.17364818, 0.34202014, 0.5       , 0.64278761]),
 array([0.98480775, 0.93969262, 0.8660254 , 0.76604444]))

In [454]: np.sin(np.radians(ITER))
Out[454]: array([0.17364818, 0.34202014, 0.5       , 0.64278761])

I don’t know whether you are just being careless, or don’t understand the basics of Python iteration.

This is all you need:

degrees = np.arange(10,50,10)
x1 = np.sin(np.radians(ITER))
y1 = np.cos(np.radians(ITER ))
XY = np.column_stack((x1, y1))

2nd try

I just noticed you use np.nditer. Why? If you are going to iterate, use the straight forward

 for degree in degress:
       ....

nditer is not a faster way of iterating; the docs may be misleading in this regard. It is really only useful as a stepping stone toward writing fancy iterations in cython. The python version is slow – and overly complicated for most users.

As the first code shows, you don’t need to iterate to calculate sin/cos for all degrees. But if you must iterate, here’s a simple clear version:

In [457]: degrees = np.arange(10,50,10)
     ...: x1, y1 = [], []
     ...: for degree in degrees:
     ...:     x1.append(np.sin(np.radians(degree)))
     ...:     y1.append(np.cos(np.radians(degree)))
     ...: XY = np.column_stack((np.array(x1), np.array(y1)))

In [458]: x1
Out[458]: 
[0.17364817766693033,
 0.3420201433256687,
 0.49999999999999994,
 0.6427876096865393]

x1,y1 are lists; list append is relatively fast, and simple. np.append is slow and hard to use correctly. Don’t use it (like nditer it needs a stronger disclaimer, and maybe even removal).

Here’s a version of iteration with np.append that works; I don’t recommend it, but it illustrates how np.append might work:

 In [461]: degrees = np.arange(10,50,10)
 ...: XY = np.zeros((0,2))
 ...: for rad in np.radians(degrees):
 ...:     XY = np.append(XY, [[np.sin(rad), np.cos(rad)]], axis=0)

I do just one np.radians conversion. No need to repeat or do it in the iteration.

I initial XY as a (0,2) array – and I add a (1,2) array to it at each iteration. np.append with axis is just

  XY = np.concatenate((XY, [[np.sin...]]), axis=0)

Your failed tries have various problems. np.array([]) has shape (0,). You can’t join a (2,) to that with axis). np.append returns a new array; it does not work in-place. None of your tries changes xy1.

Looking more at that second block of code, I get the impression that you are just being careless. You mix xy1, x1, y1, a, XY without paying attention to how they might, or might not, be related.

Answered By: hpaulj
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.