Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I unpack a numpy array of tuples into an ndarray?

Tags:

python

numpy

I have a 2D numpy array with elements of the type np.void that are essentially tuples. Is there an efficient way to unpack the values in these tuples to a 3rd dimension without looping through each element of the array?

For example, the 2D array looks something like:

a = np.array([[(1, 2,  3), (1, 2,  3), (1, 2, 3)],
       [(1, 2,  3), (1, 2, 3), (1, 2, 3)],
       [(1, 2, 3), (1, 2, 3), (1, 2, 3)]],
      dtype=[('B4', '<u2'), ('B3', '<u2'), ('B2', '<u2')])

Where,

a.shape = (3,3)
a[0,0] = (1,2,3)

I'd like to unpack each element so the resulting array would be 3D and look something like this:

b.shape = (3,3,3)
b[0,0,0] = 1
b[0,0,1] = 2
b[0,0,2] = 3

in other words,

b[:,:,0] == 
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]])
b[:,:,1] == 
array([[2, 2, 2],
       [2, 2, 2],
       [2, 2, 2]])
b[:,:,2] == 
array([[3, 3, 3],
       [3, 3, 3],
       [3, 3, 3]])

I know there's gotta be a more efficient way to do this other than looping through each element, but I'm not really familiar with dealing with np.void elements.

Thanks

To clarify, a more efficient solution meaning compared to something like

new_array = np.zeros((a.shape + (3,)))
for i in range(a.shape[0]):
    for j in range(a.shape[-1]):
        new_array[i, j, 0] = a[i, j][0]
        new_array[i, j, 1] = a[i, j][1]
        new_array[i, j, 2] = a[i, j][2]
like image 820
Brenton Avatar asked Oct 22 '25 18:10

Brenton


1 Answers

In [601]: a = np.array([[(1, 2,  3), (1, 2,  3), (1, 2, 3)], 
     ...:        [(1, 2,  3), (1, 2, 3), (1, 2, 3)], 
     ...:        [(1, 2, 3), (1, 2, 3), (1, 2, 3)]], 
     ...:       dtype=[('B4', '<u2'), ('B3', '<u2'), ('B2', '<u2')])                 
In [602]: a.dtype                                                                    
Out[602]: dtype([('B4', '<u2'), ('B3', '<u2'), ('B2', '<u2')])
In [603]: a.shape                                                                    
Out[603]: (3, 3)

This is a structured array, with a compound dtype. The tuples display individual elements of the 2d array.

Recent numpy versions have added a function to conveniently convert structured arrays to unstructured:

In [606]: b=rf.structured_to_unstructured(a)                                         
In [607]: b                                                                          
Out[607]: 
array([[[1, 2, 3],
        [1, 2, 3],
        [1, 2, 3]],

       [[1, 2, 3],
        [1, 2, 3],
        [1, 2, 3]],

       [[1, 2, 3],
        [1, 2, 3],
        [1, 2, 3]]], dtype=uint16)
In [608]: b[:,:,1]                                                                   
Out[608]: 
array([[2, 2, 2],
       [2, 2, 2],
       [2, 2, 2]], dtype=uint16)

a has 3 fields. Individual fields can be accessed by name:

In [610]: a['B4']                                                                    
Out[610]: 
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]], dtype=uint16)

That means you could construct the 3d array by concatenating the 3 individual fields:

np.stack([a['B4'],a['B3'],a['B2']]) 

This is like your last solution, but without the i,j iteration.


The view approach in the other answer works in this case because all fields have the same dtype, <u2. That means the same underlying data can be viewed as individual <u2 elements, or a groups of 3 of these.

import numpy.lib.recfunctions as rf

The rf.structured_to_unstructured works in more general cases where view does not, such as a mix of dtypes, (e.g. floats and integers).

like image 106
hpaulj Avatar answered Oct 24 '25 08:10

hpaulj



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!