forcing a creation of 1d numpy array from a list/array of possibly iterable objects

Viewed 235

I'm trying to see if there is a prettier way to create (i.e force the creation) of a 1d numpy array from another list/array of objects. These objects, however, may have entries that are themselves iterable (so they can be lists, tuples, etc. but can also be more arbitrary objects).

So to make things really simple, let me consider the following scenario:

a=[(1,2), (3,4), (3,5)]
b=np.array(a, dtype=object)
b.shape # gives (2,3), but I would like to have (3,1) or (3,)

I was wondering if there is a nice pythonic/numpy'ish way to force b to have a shape (3,), and the iterable structure of the elements of a to be neglected in b. Right now I do this:

a=[(1,2), (3,4), (3,5)]
b=np.empty(len(a), dtype=object)
for i,x in enumerate(a):
    b[i]=x
b.shape # gives (3,) this is what i want. 

which works, but a bit ugly. I could not find a nicer way to do this in way that's more built-in into numpy. Any ideas?

(more context: what I really need to do is reshuffle the dimensions of b in various ways, hence I don't want b to know anything about the dimensions of its elements if they are iterable). Thanks!

1 Answers
In [60]: b = np.empty(3, object)         

You don't need to iterate when assigning from a list:

In [61]: b[:] = [(1,2),(3,4),(3,5)]                                                            
In [62]: b                                                                                     
Out[62]: array([(1, 2), (3, 4), (3, 5)], dtype=object)
In [63]: b.shape                                                                               
Out[63]: (3,)

For an array it doesn't work:

In [64]: b[:] = np.array([(1,2),(3,4),(3,5)])                                                  
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-64-3042dce1f885> in <module>
----> 1 b[:] = np.array([(1,2),(3,4),(3,5)])

ValueError: could not broadcast input array from shape (3,2) into shape (3)

You may have use the iteration in the array case:

In [66]: for i,n in  enumerate(np.array([(1,2),(3,4),(3,5)])): 
    ...:     b[i] = n 
    ...:                                                                                       
In [67]: b                                                                                     
Out[67]: array([array([1, 2]), array([3, 4]), array([3, 5])], dtype=object)

Keep in mind that object dtype arrays are a bit of fall back option. np.array(...) tries to create a multidimensional array if possible (with numeric dtype). Making an object dtype is done only if that isn't possible. And for some combinations of shapes, it throws up its hands and raises an error.

Turning that array into a list of arrays with list() also works (same speed):

In [92]: b[:] = list(np.array([(1,2),(3,4),(3,5)]))                                            
In [93]: b                                                                                     
Out[93]: array([array([1, 2]), array([3, 4]), array([3, 5])], dtype=object)
Related