Search code examples
pythonarraysnumpycastinguser-defined-types

convert (nx2) array of floats into (nx1) array of 2-tuples


I have a NumPy float array

x = np.array([
    [0.0, 1.0],
    [2.0, 3.0],
    [4.0, 5.0]
    ],
    dtype=np.float32
    )

and need to convert it into a NumPy array with a tuple dtype,

y = np.array([
    (0.0, 1.0),
    (2.0, 3.0),
    (4.0, 5.0)
    ],
    dtype=np.dtype((np.float32, 2))
    )

NumPy views unfortunately don't work here:

y = x.view(dtype=np.dtype((np.float32, 2)))
ValueError: new type not compatible with array.

Is there a chance to get this done without iterating through x and copying over every single entry?


Solution

  • This is close:

    In [122]: dt=np.dtype([('x',float,(2,))])
    
    In [123]: y=np.zeros(x.shape[0],dtype=dt)
    
    In [124]: y
    Out[124]: 
    array([([0.0, 0.0],), ([0.0, 0.0],), ([0.0, 0.0],)], 
          dtype=[('x', '<f8', (2,))])
    
    In [125]: y['x']=x
    
    In [126]: y
    Out[126]: 
    array([([0.0, 1.0],), ([2.0, 3.0],), ([4.0, 5.0],)], 
          dtype=[('x', '<f8', (2,))])
    
    In [127]: y['x']
    Out[127]: 
    array([[ 0.,  1.],
           [ 2.,  3.],
           [ 4.,  5.]])
    

    y has one compound field. That field has 2 elements.

    Alternatively you could define 2 fields:

    In [134]: dt=np.dtype('f,f')
    In [135]: x.view(dt)
    Out[135]: 
    array([[(0.0, 1.0)],
           [(2.0, 3.0)],
           [(4.0, 5.0)]], 
          dtype=[('f0', '<f4'), ('f1', '<f4')])
    

    But that is shape (3,1); so reshape:

    In [137]: x.view(dt).reshape(3)
    Out[137]: 
    array([(0.0, 1.0), (2.0, 3.0), (4.0, 5.0)], 
          dtype=[('f0', '<f4'), ('f1', '<f4')])
    

    Apart from the dtype that displays the same as your y.