3

If someone could help with this, I'd be very grateful as it's been driving me a bit crazy for a couple of hours!

I have an ndarray as follows:

array([[[0, 0],
        [0, 2],
        [0, 4]],
       [[1, 0],
        [1, 2],
        [1, 4]]])

I would like to convert this to a record array:

array([[(0, 0),
        (0, 2),
        (0, 4)],
       [(1, 0),
        (1, 2),
        (1, 4)]],
      dtype=[('x', '<i4'), ('y', '<i4')])
MSeifert
  • 145,886
  • 38
  • 333
  • 352
MarkNS
  • 3,811
  • 2
  • 43
  • 60

1 Answers1

5

You can simply use .view to "change" the dtype and .reshape to "remove" the last dimension:

>>> import numpy as np

>>> arr = np.array([[[0, 0], [0, 2], [0, 4]],
...                 [[1, 0], [1, 2], [1, 4]]])

>>> newarr = arr.view(dtype=np.dtype([('x', 'i4'), ('y', 'i4')]))
>>> newarr = newarr.reshape(newarr.shape[:-1])
>>> newarr
array([[(0, 0), (0, 2), (0, 4)],
       [(1, 0), (1, 2), (1, 4)]], 
      dtype=[('x', '<i4'), ('y', '<i4')])

Note that you have to be careful with .view, hardcoding the dtype might be not "safe" here. But you can simply reuse the current dtype:

>>> newarr = arr.view(dtype=np.dtype([('x', arr.dtype), ('y', arr.dtype)]))
MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • Thanks for this - I'm getting a "ValueError: total size of new array must be unchanged" or the reshape however. Numpy 1.11.2. Any ideas? – MarkNS Apr 15 '17 at 12:38
  • @MarkNS When you run the code that I posted? Or in your own code? – MSeifert Apr 15 '17 at 12:40
  • Using exactly the code you posted: arr = np.array([[[0, 0], [0, 2], [0, 4]], [[1, 0], [1, 2], [1, 4]]]) newarr = arr.view(dtype=np.dtype([('x', 'i4'), ('y', 'i4')])) newarr = newarr.reshape(newarr.shape[:-1]) Traceback (most recent call last): File "/Volumes/Users/markns/miniconda3/envs/alder/lib/python3.5/site-... File "", line 1, in newarr = newarr.reshape(newarr.shape[:-1]) ValueError: total size of new array must be unchanged – MarkNS Apr 15 '17 at 12:42
  • could you try it with the `newarr = arr.view(dtype=np.dtype([('x', arr.dtype), ('y', arr.dtype)]))` instead of `newarr = arr.view(dtype=np.dtype([('x', 'i4'), ('y', 'i4')]))`? – MSeifert Apr 15 '17 at 12:44
  • That need squeeze out that last dimension bugs me. And you have to add one back in when going the other direction. Sometimes I've recommended a `tolist` intermediary, http://stackoverflow.com/a/43396313/901925, especially when going from structured to regular. – hpaulj Apr 15 '17 at 16:20
  • @hpaulj the reshaping or squeeze might be a nuisance, but at least it's a very cheap operation - `tolist` isn't even if it's definetly "shorter". – MSeifert Apr 15 '17 at 17:40
  • `squeeze(axis=-1)` is a little shorter – Eric Apr 16 '17 at 11:11
  • viewing to and from `np.complex` has the same issue. A singular dimension is retained. Some sort of logic may require it, but it still feels like a rough edge. – hpaulj Apr 16 '17 at 15:31