user2909415
user2909415

Reputation: 1029

Numpy: vector of indices and value

I guess I'm having a slow day and can't figure this one out. I have an m x n numpy array and want to convert it to a vector where each element is a 3 dimensional vector containing the row number, column number and value of all the elements in the array.

For example, given an numpy array, a, the first element in the vector would be: [1, 1, a[1, 1]] then the next would be [1, 2, a[1, 2]] etc.

Upvotes: 1

Views: 1248

Answers (2)

hpaulj
hpaulj

Reputation: 231738

This sequence produces a (3, n*m) array with the indices and values

In [786]: A = np.arange(12).reshape(3,4)
In [787]: X=np.vstack([np.indices(A.shape),A[None,...]]).reshape(3,-1)
In [788]: X.shape
Out[788]: (3, 12)
In [789]: X
Out[789]: 
array([[ 0,  0,  0,  0,  1,  1,  1,  1,  2,  2,  2,  2],
       [ 0,  1,  2,  3,  0,  1,  2,  3,  0,  1,  2,  3],
       [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11]])

It can be transposed to make each 'row' represent an element:

In [793]: X.T[0,:]
Out[793]: array([0, 0, 0])
In [794]: X.T[10,:]
Out[794]: array([ 2,  2, 10])

It could also be cast into a structured array with length (n*m,), and dtype('i4,i4,i4'). This example is a bit messy, but it does job:

In [796]: dt=np.dtype('i4,i4,i4')
In [806]: X1=np.zeros(X.shape[1],dtype=dt)
In [809]: X1['f0']=X[0]
In [810]: X1['f1']=X[1]
In [811]: X1['f2']=X[2]
# or more compactly: for i,n in enumerate(X1.dtype.names): X1[n] = X[i,:]
In [812]: X1
Out[812]: 
array([(0, 0, 0), (0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 0, 4), (1, 1, 5),
       (1, 2, 6), (1, 3, 7), (2, 0, 8), (2, 1, 9), (2, 2, 10), (2, 3, 11)], 
      dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')])
In [813]: X1[10]
Out[813]: (2, 2, 10)   # note, this a tuple
In [814]: X1['f2']
Out[814]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

Lets say the original matrix is floats, and we want to preserve that type in the new array. We could do that by skipping the vstack step:

In [833]: A = np.arange(12,dtype=float).reshape(3,4)
In [834]: X = np.indices(A.shape).reshape(2,-1)
...
In [848]: dt=np.dtype([('row',int), ('col',int), ('value',float)])
In [850]: X1 = np.zeros(X.shape[1], dtype=dt)
In [851]: X1['row']=X[0,:]
In [852]: X1['col']=X[1,:]
In [853]: X1['value']=A.flatten()
In [854]: X1
Out[854]: 
array([(0, 0, 0.0), (0, 1, 1.0), (0, 2, 2.0), (0, 3, 3.0), (1, 0, 4.0),
       (1, 1, 5.0), (1, 2, 6.0), (1, 3, 7.0), (2, 0, 8.0), (2, 1, 9.0),
       (2, 2, 10.0), (2, 3, 11.0)], 
      dtype=[('row', '<i4'), ('col', '<i4'), ('value', '<f8')])
In [855]: X1[10]
Out[855]: (2, 2, 10.0)

X1[10] is a 0D array with dtype dt, and shape (), which prints as a tuple.

Upvotes: 1

Alok--
Alok--

Reputation: 724

I think something like this should work:

n = 10
m = 5

data = np.random.randn(n, m)
grid = np.indices(data.shape)
r = np.array([grid[0], grid[1], data])
result = np.array(zip(*r.T))

There are probably more efficient ways to do this though. See: numpy.indices

Upvotes: 1

Related Questions