1

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?

2 Answers 2

2

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.

1
  • Thanks @joris, this is perfect. Using a view, I could actually change the array in-place, by doing: constants = constants.view([('constants',dt)]) Commented Jan 7, 2013 at 13:25
0

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?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.