Home > database >  Is it possible to convert numbers in an array to tuple enumerating with python?
Is it possible to convert numbers in an array to tuple enumerating with python?

Time:09-28

I have an example array:

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

Desired output:

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

I applied this:

np.apply_along_axis(lambda tuple(enumerate(x)), 1, arr)

I got different output:

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

       [[0, 3],
        [1, 4],
        [2, 2]],

       [[0, 3],
        [1, 6],
        [2, 1]]])

CodePudding user response:

Usually you don't have tuples in a numpy array. Your output is basically what you desire but as lists and not as tuples. You can use a workaround like shown here:

import numpy as np

def return_tuple(x):
    out = np.empty(len(x), dtype=object)
    out[:] = list(enumerate(x))
    return out

arr = np.array([[2,4,1],[3,4,2],[3,6,1]])
result = np.apply_along_axis(return_tuple, 1, arr)
print(result)
print(type(result))

[[(0, 2) (1, 4) (2, 1)]
 [(0, 3) (1, 4) (2, 2)]
 [(0, 3) (1, 6) (2, 1)]]
<class 'numpy.ndarray'>

CodePudding user response:

np.apply_along_axis, np.vectorize, and friends are not actually vectorized functions. The "undesired" output you show is what you get when you want to have a numerical array: you can index it the same as the array of tuples, and everything about it is better, except that it may not look as pretty. A faster way to make this array is

>>> np.stack((np.broadcast_to(np.arange(arr.shape[1]), arr.shape), arr), axis=-1)
array([[[0, 2],
        [1, 4],
        [2, 1]],

       [[0, 3],
        [1, 4],
        [2, 2]],

       [[0, 3],
        [1, 6],
        [2, 1]]])

Sure this looks wrong, but just get rid of a couple of newlines and you get

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

If you absolutely insist on having parenthes around your elements, you can do this without losing numpyness (i.e., contiguous blocks of numbers) by making a recarray with a custom dtype:

>>> result = np.empty_like(arr, dtype=[('i', int), ('x', arr.dtype)])
>>> result['x'] = arr
>>> result['i'] = np.arange(arr.shape[0])

And lo and behold, you get pretty parentheses:

array([[(0, 2), (1, 4), (2, 1)],
       [(0, 3), (1, 4), (2, 2)],
       [(0, 3), (1, 6), (2, 1)]], dtype=[('i', '<i4'), ('x', '<i4')])
  • Related