Reputation: 46530
I would like to take an existing array with several named fields, and create a new array (or change it in place) with one field with a hierarchical dtype equal to the original dtype. That is,
newarray = np.array(oldarray, dtype=[('old',oldarray.dtype)])
such that newarray['old']
is identical in shape and structure to oldarray
Here's an example:
In [1]: import numpy as np
In [2]: dt = np.dtype([('name',np.str_,2),('val',np.float_)])
In [3]: constants = np.array([('pi',3.14),('e',2.72)],dtype=dt)
In [4]: constants
Out[4]:
array([('pi', 3.14), ('e', 2.72)],
dtype=[('name', '|S2'), ('val', '<f8')])
In [5]: numbers = constants.astype([('constants',dt)])
But this gives me all zeros:
In [6]: numbers
Out[6]:
array([(('', 0.0),), (('', 0.0),)],
dtype=[('constants', [('name', '|S2'), ('val', '<f8')])])
I have the same problem if I try to make a copy:
In [7]: numbers = np.array(constants,dtype=[('constants',dt)])
In [8]: numbers
Out[8]:
array([(('', 0.0),), (('', 0.0),)],
dtype=[('constants', [('name', '|S2'), ('val', '<f8')])])
Also: Does anybody know why this is happening?
Upvotes: 1
Views: 580
Reputation: 139142
You can take a view
of the original array with the new dtype (http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.view.html):
>>> import numpy as np
>>> dt = np.dtype([('name',np.str_,2),('val',np.float_)])
>>> constants = np.array([('pi',3.14),('e',2.72)],dtype=dt)
>>>
>>> numbers = constants.view([('constants',dt)])
>>>
>>> numbers['constants']
array([('pi', 3.14), ('e', 2.72)],
dtype=[('name', '|S2'), ('val', '<f8')])
Be aware that the resulting array numbers
is a view of the origingal array, so changes in one of them will also affect the other.
Upvotes: 2
Reputation: 46530
I can solve the problem by making a list of the original array:
In [9]: numbers = np.array([constants],dtype=[('constants',dt)])
In [10]: numbers
Out[10]:
array([[(('pi', 3.14),), (('e', 2.72),)]],
dtype=[('constants', [('name', '|S2'), ('val', '<f8')])])
But when I look at it, of course I have an extra nesting in the list:
In [11]: numbers['constants']
Out[11]:
array([[('pi', 3.14), ('e', 2.72)]],
dtype=[('name', '|S2'), ('val', '<f8')])
In [12]: numbers['constants']['name']
Out[12]:
array([['pi', 'e']],
dtype='|S2')
I really just want the first item in the list:
In [13]: numbers[0]
Out[13]:
array([(('pi', 3.14),), (('e', 2.72),)],
dtype=[('constants', [('name', '|S2'), ('val', '<f8')])])
I can also achieve this by flattening the array afterward:
In [14]: numbers.flatten()
Out[14]:
array([(('pi', 3.14),), (('e', 2.72),)],
dtype=[('constants', [('name', '|S2'), ('val', '<f8')])])
In [15]: numbers.flatten()['constants']
Out[15]:
array([('pi', 3.14), ('e', 2.72)],
dtype=[('name', '|S2'), ('val', '<f8')])
In [16]: numbers.flatten()['constants']['name']
Out[16]:
array(['pi', 'e'],
dtype='|S2')
But isn't that a hack? What I really want in the end is this array:
In [17]: numbers = np.array([(('pi', 3.14),), (('e', 2.72),)],dtype=[('constants',dt)])
In [18]: numbers['constants']
Out[18]:
array([('pi', 3.14), ('e', 2.72)],
dtype=[('name', '|S2'), ('val', '<f8')])
In [19]: numbers['constants']['name']
Out[19]:
array(['pi', 'e'],
dtype='|S2')
Without having to make a one-item list and then flatten it. Any better ideas?
Upvotes: 0