001001
001001

Reputation: 588

How to add or construct nested numpy structured array from existing structures

In general, my question is on the possible ways for creating/appending to nested structured arrays. Specifically where the dtype structure is known, but the size in the nested elements weren't pre-defined. I have tried different things with the join_by and fromarray methods, but haven't had success. The doc examples seem to suggest the join type methods are useful for a sort of 'zipping' of data and not really extending it?

Datatypes defined

from numpy.lib import recfunctions as rfn
c = [('x','f8'),('y','f8')]
d = [('text','|S20'),('val', c)]

Creates 2 rows of 'd'

zeros = np.zeros(2, dtype=d)
print(f'{zeros=}')

How to make multiple rows of 'c'?

c = [('x','f8'),('y','f8')]
# Add a number to the construct for 'c'
d = [('text','|S20'),('val', c, 3)]
zeros = np.zeros(2, dtype=d)
print(f'{zeros=}')

How to do this without predefining the size of 'c'? Appending/Extending nested elements doesn't seem to work At the lowest level, 'c' can be used to construct a recarray

large_c = np.arange(2*3).reshape(3,2)
struct_c = rfn.unstructured_to_structured(large_c, np.dtype(c))
print(f'{struct_c=}')

But now, is there a way to construct the next level from existing structured arrays? I thought constructing an array with a shape that seems to broadcast would work, but it fails

struct_d = rfn.unstructured_to_structured(np.array(['', large_c]), np.dtype(d))
print(f'{struct_d=}')
>> The length of the last dimension of arr must be equal to the number of fields in dtype

I also tried the recarray constructions, which had their own issues

struct_d = np.core.records.fromarrays(np.array(['', large_c]), dtype=d)
print(f'{struct_d=}')
>>> array-shape mismatch in array 1

Upvotes: 0

Views: 250

Answers (1)

hpaulj
hpaulj

Reputation: 231335

I think the most straightforward way of making such an array is:

In [352]: c = [('x','f8'),('y','f8')]
     ...: # Add a number to the construct for 'c'
     ...: d = [('text','|S20'),('val', c, 3)]
     ...: zeros = np.zeros(2, dtype=d)
In [353]: zeros
Out[353]: 
array([(b'', [(0., 0.), (0., 0.), (0., 0.)]),
       (b'', [(0., 0.), (0., 0.), (0., 0.)])],
      dtype=[('text', 'S20'), ('val', [('x', '<f8'), ('y', '<f8')], (3,))])

In [355]: x = np.arange(12).reshape(2,3,2)

In [357]: carr = rf.unstructured_to_structured(x,np.dtype(c))
In [358]: carr
Out[358]: 
array([[( 0.,  1.), ( 2.,  3.), ( 4.,  5.)],
       [( 6.,  7.), ( 8.,  9.), (10., 11.)]],
      dtype=[('x', '<f8'), ('y', '<f8')])

With the right shape and dtype, it can be assigned to the larger array:

In [359]: zeros['val']=carr
In [360]: zeros
Out[360]: 
array([(b'', [( 0.,  1.), ( 2.,  3.), ( 4.,  5.)]),
       (b'', [( 6.,  7.), ( 8.,  9.), (10., 11.)])],
      dtype=[('text', 'S20'), ('val', [('x', '<f8'), ('y', '<f8')], (3,))])

I'm not sure if there's something in your question that I glossed over or not.

Upvotes: 0

Related Questions