Add row and column numbers to np array - python

I have a numpy array of shape (1024, 1024, 3). It is an image RGB converted to a numpy array. I want to add the row and column number of the pixel to the numpy array.
Given a numpy array of shape (1024, 1024, 3). How do I convert it to a numpy array of (1024, 1024, 5) with the additional columns being row and column number of the particular pixel?
If one of the cell values is [125, 125, 125] and it is the 5th row and 3rd column, I want to convert it to [5, 3, 125, 125, 125]

Here is a method using np.indices and np.r_:
# small test case
>>> a = np.arange(108).reshape(6, 6, 3)
# create indices
>>> i, j = np.indices(a.shape[:2])
# stack them
>>> result = np.r_["2,3,0", i, j, a]
# admire
>>> result
array([[[ 0, 0, 0, 1, 2],
[ 0, 1, 3, 4, 5],
[ 0, 2, 6, 7, 8],
[ 0, 3, 9, 10, 11],
[ 0, 4, 12, 13, 14],
[ 0, 5, 15, 16, 17]],
[[ 1, 0, 18, 19, 20],
[ 1, 1, 21, 22, 23],
[ 1, 2, 24, 25, 26],
[ 1, 3, 27, 28, 29],
[ 1, 4, 30, 31, 32],
[ 1, 5, 33, 34, 35]],
[[ 2, 0, 36, 37, 38],
[ 2, 1, 39, 40, 41],
[ 2, 2, 42, 43, 44],
[ 2, 3, 45, 46, 47],
[ 2, 4, 48, 49, 50],
[ 2, 5, 51, 52, 53]],
[[ 3, 0, 54, 55, 56],
[ 3, 1, 57, 58, 59],
[ 3, 2, 60, 61, 62],
[ 3, 3, 63, 64, 65],
[ 3, 4, 66, 67, 68],
[ 3, 5, 69, 70, 71]],
[[ 4, 0, 72, 73, 74],
[ 4, 1, 75, 76, 77],
[ 4, 2, 78, 79, 80],
[ 4, 3, 81, 82, 83],
[ 4, 4, 84, 85, 86],
[ 4, 5, 87, 88, 89]],
[[ 5, 0, 90, 91, 92],
[ 5, 1, 93, 94, 95],
[ 5, 2, 96, 97, 98],
[ 5, 3, 99, 100, 101],
[ 5, 4, 102, 103, 104],
[ 5, 5, 105, 106, 107]]])

Related

duplicating last column of 3d numpy array

I have the following numpy 3d array, in which I need to duplicate the last column
array([[[ 7, 5, 93],
[19, 4, 69],
[62, 2, 52]],
[[ 6, 1, 65],
[41, 9, 94],
[39, 4, 49]]])
The desired output is:
array([[[ 7, 5, 93, 93],
[19, 4, 69, 69],
[62, 2, 52, 52]],
[[ 6, 1, 65, 65],
[41, 9, 94, 94],
[39, 4, 49, 49]]])
Is there a clever way of doing this?
You could concatenate along the last axis as follows-
numpy.concatenate([a, numpy.expand_dims(a[:, :, -1], axis=2)], axis=2)
There is a built-in numpy function for this purpose:
np.insert(x,-1,x[...,-1],-1)
output:
array([[[ 7, 5, 93, 93],
[19, 4, 69, 69],
[62, 2, 52, 52]],
[[ 6, 1, 65, 65],
[41, 9, 94, 94],
[39, 4, 49, 49]]])

Vectorizing assignment of a tensor to a slice in PyTorch

I'm trying to vectorize a slice assignment of the form
for i in range(a.shape[1]):
for j in range(a.shape[2]):
a[:,i,j,:,i:i+b.shape[2],j:j+b.shape[3]] = b
where b itself is an array. This is because the nested Python loop is too inefficient and is taking up most of the runtime. Is there a way to do this?
For a simpler case, consider the following:
for i in range(a.shape[1]):
a[:,i,:,i:i+b.shape[2]] = b
This is what b and a might look like:
You can see the diagonal, "sliding" structure of the resulting matrix.
We can leverage np.lib.stride_tricks.as_strided based scikit-image's view_as_windows to get sliding windowed views into a 0s padded version of the input and being a view would be efficient on memory and performance. More info on use of as_strided based view_as_windows.
Hence, for the simpler case, it would be -
from skimage.util.shape import view_as_windows
def sliding_2D_windows(b, outshp_axis1):
# outshp_axis1 is desired output's shape along axis=1
n = outshp_axis1-1
b1 = np.pad(b,((0,0),(0,0),(n,n)),'constant')
w_shp = (1,b1.shape[1],b.shape[2]+n)
return view_as_windows(b1,w_shp)[...,0,::-1,0,:,:]
Sample run -
In [192]: b
Out[192]:
array([[[54, 57, 74, 77],
[77, 19, 93, 31],
[46, 97, 80, 98]],
[[98, 22, 68, 75],
[49, 97, 56, 98],
[91, 47, 35, 87]]])
In [193]: sliding_2D_windows(b, outshp_axis1=3)
Out[193]:
array([[[[54, 57, 74, 77, 0, 0],
[77, 19, 93, 31, 0, 0],
[46, 97, 80, 98, 0, 0]],
[[ 0, 54, 57, 74, 77, 0],
[ 0, 77, 19, 93, 31, 0],
[ 0, 46, 97, 80, 98, 0]],
[[ 0, 0, 54, 57, 74, 77],
[ 0, 0, 77, 19, 93, 31],
[ 0, 0, 46, 97, 80, 98]]],
[[[98, 22, 68, 75, 0, 0],
[49, 97, 56, 98, 0, 0],
[91, 47, 35, 87, 0, 0]],
....
[[ 0, 0, 98, 22, 68, 75],
[ 0, 0, 49, 97, 56, 98],
[ 0, 0, 91, 47, 35, 87]]]])
Assuming b has a shape (2,3,x1), and a has a shape (2,x2-x1+1,3,x2). In your screenshot, we can infer that x1=4, x2=6.
import numpy as np
b_shape = (2,3,4)
a_shape = (2,3,3,6)
b = np.arange(1,25).reshape(b_shape)
#array([[[ 1, 2, 3, 4],
# [ 5, 6, 7, 8],
# [ 9, 10, 11, 12]],
#
# [[13, 14, 15, 16],
# [17, 18, 19, 20],
# [21, 22, 23, 24]]])
c = np.pad(b, (*[(0,0) for _ in range(len(b_shape[:-1]))], (0,a_shape[-1]-b_shape[-1])), 'constant')
#array([[[ 1, 2, 3, 4, 0, 0],
# [ 5, 6, 7, 8, 0, 0],
# [ 9, 10, 11, 12, 0, 0]],
#
# [[13, 14, 15, 16, 0, 0],
# [17, 18, 19, 20, 0, 0],
# [21, 22, 23, 24, 0, 0]]])
a = np.stack([np.roll(c, shift=i) for i in range(a_shape[-1]-b_shape[-1]+1)], axis=1)
# array([[[[ 1, 2, 3, 4, 0, 0],
# [ 5, 6, 7, 8, 0, 0],
# [ 9, 10, 11, 12, 0, 0]],
# [[ 0, 1, 2, 3, 4, 0],
# [ 0, 5, 6, 7, 8, 0],
# [ 0, 9, 10, 11, 12, 0]],
# [[ 0, 0, 1, 2, 3, 4],
# [ 0, 0, 5, 6, 7, 8],
# [ 0, 0, 9, 10, 11, 12]]],
# [[[13, 14, 15, 16, 0, 0],
# [17, 18, 19, 20, 0, 0],
# [21, 22, 23, 24, 0, 0]],
# [[ 0, 13, 14, 15, 16, 0],
# [ 0, 17, 18, 19, 20, 0],
# [ 0, 21, 22, 23, 24, 0]],
# [[ 0, 0, 13, 14, 15, 16],
# [ 0, 0, 17, 18, 19, 20],
# [ 0, 0, 21, 22, 23, 24]]]])

Is layered broadcasting available in NumPy?

I wonder if there is a built-in operation which would free my code from Python-loops.
The problem is this: I have two matrices A and B. A has N rows and B has N columns. I would like to multiply every i row from A with corresponding i column from B (using NumPy broadcasting). The resulting matrix would form i layer in the output. So my result would be 3-dimensional array.
Is such operation available in NumPy?
One way to express your requirement directly is by using np.einsum():
>>> A = np.arange(12).reshape(3, 4)
>>> B = np.arange(15).reshape(5, 3)
>>> np.einsum('...i,j...->...ij', A, B)
array([[[ 0, 0, 0, 0, 0],
[ 0, 3, 6, 9, 12],
[ 0, 6, 12, 18, 24],
[ 0, 9, 18, 27, 36]],
[[ 4, 16, 28, 40, 52],
[ 5, 20, 35, 50, 65],
[ 6, 24, 42, 60, 78],
[ 7, 28, 49, 70, 91]],
[[ 16, 40, 64, 88, 112],
[ 18, 45, 72, 99, 126],
[ 20, 50, 80, 110, 140],
[ 22, 55, 88, 121, 154]]])
This uses the Einstein summation convention.
For further discussion, see chapter 3 of Vectors, Pure and Applied: A General Introduction to Linear Algebra by T. W. Körner. In it, the author cites an amusing passage from Einstein's letter to a friend:
"I have made a great discovery in mathematics; I have suppressed the summation sign every time that the summation must be made over an index which occurs twice..."
Yes, in it's simplest form you just add "zero" dimensions so the NumPy broadcasts along the rows of A and columns of B:
>>> import numpy as np
>>> A = np.arange(12).reshape(3, 4) # 3 row, 4 colums
>>> B = np.arange(15).reshape(5, 3) # 5 rows, 3 columns
>>> res = A[None, ...] * B[..., None]
>>> res
array([[[ 0, 0, 0, 0],
[ 4, 5, 6, 7],
[ 16, 18, 20, 22]],
[[ 0, 3, 6, 9],
[ 16, 20, 24, 28],
[ 40, 45, 50, 55]],
[[ 0, 6, 12, 18],
[ 28, 35, 42, 49],
[ 64, 72, 80, 88]],
[[ 0, 9, 18, 27],
[ 40, 50, 60, 70],
[ 88, 99, 110, 121]],
[[ 0, 12, 24, 36],
[ 52, 65, 78, 91],
[112, 126, 140, 154]]])
The result has a shape of (5, 3, 4) and you can easily move the axis around if you want a different shape. For example using np.moveaxis:
>>> np.moveaxis(res, (0, 1, 2), (2, 0, 1)) # 0 -> 2 ; 1 -> 0, 2 -> 1
array([[[ 0, 0, 0, 0, 0],
[ 0, 3, 6, 9, 12],
[ 0, 6, 12, 18, 24],
[ 0, 9, 18, 27, 36]],
[[ 4, 16, 28, 40, 52],
[ 5, 20, 35, 50, 65],
[ 6, 24, 42, 60, 78],
[ 7, 28, 49, 70, 91]],
[[ 16, 40, 64, 88, 112],
[ 18, 45, 72, 99, 126],
[ 20, 50, 80, 110, 140],
[ 22, 55, 88, 121, 154]]])
With a shape of (3, 4, 5).

Generalisation of vector outer product: apply it to every column of a matrix

I have a matrix A = [x1, x2, ..., xm] where each xi is a column vector of size [n, 1]. So A has shape [n, m]. I am trying to find the covariance matrix of each column vector so that if the result is another matrix C, C has shape [n, n, m] and C[:,:,i] = np.outer(xi, xi).
Can someone tell my how to do the above in numpy or point me to a tensor operation that I should check out?
So your outer loop produces:
In [1147]: A = np.arange(12).reshape(3,4)
In [1148]: [np.outer(A[:,i],A[:,i]) for i in range(4)]
Out[1148]:
[array([[ 0, 0, 0],
[ 0, 16, 32],
[ 0, 32, 64]]), array([[ 1, 5, 9],
[ 5, 25, 45],
[ 9, 45, 81]]), array([[ 4, 12, 20],
[ 12, 36, 60],
[ 20, 60, 100]]), array([[ 9, 21, 33],
[ 21, 49, 77],
[ 33, 77, 121]])]
stacking that on the a new 1st dimension produces:
In [1149]: np.stack(_)
Out[1149]:
array([[[ 0, 0, 0],
[ 0, 16, 32],
[ 0, 32, 64]],
....
[ 21, 49, 77],
[ 33, 77, 121]]])
In [1150]: _.shape
Out[1150]: (4, 3, 3) # wrong order - can be transposed.
stack lets us specify a different axis:
In [1153]: np.stack([np.outer(A[:,i],A[:,i]) for i in range(4)],2)
Out[1153]:
array([[[ 0, 1, 4, 9],
[ 0, 5, 12, 21],
[ 0, 9, 20, 33]],
[[ 0, 5, 12, 21],
[ 16, 25, 36, 49],
[ 32, 45, 60, 77]],
[[ 0, 9, 20, 33],
[ 32, 45, 60, 77],
[ 64, 81, 100, 121]]])
np.einsum does this nicely as well:
In [1151]: np.einsum('mi,ni->mni',A,A)
Out[1151]:
array([[[ 0, 1, 4, 9],
[ 0, 5, 12, 21],
[ 0, 9, 20, 33]],
[[ 0, 5, 12, 21],
[ 16, 25, 36, 49],
[ 32, 45, 60, 77]],
[[ 0, 9, 20, 33],
[ 32, 45, 60, 77],
[ 64, 81, 100, 121]]])
In [1152]: _.shape
Out[1152]: (3, 3, 4)
broadcasted multiply is also nice
In [1156]: A[:,None,:]*A[None,:,:]
Out[1156]:
array([[[ 0, 1, 4, 9],
[ 0, 5, 12, 21],
...
[ 32, 45, 60, 77],
[ 64, 81, 100, 121]]])

separating mutidimensional array numpy python

i have a numpy array like the following
[[ 1 2 3 4 ]
[ 5 6 7 8 ]
......... ]
So basically I want to create 4 (can be different) lists where
list_1 = [1,5...], list_2 = [2,6....] and so on.
What is the pythonic way to do this?
Given a numpy array
>>> numpy.array([[x for x in xrange(i,i+5)] for i in xrange(0,100,10)])
array([[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24],
[30, 31, 32, 33, 34],
[40, 41, 42, 43, 44],
[50, 51, 52, 53, 54],
[60, 61, 62, 63, 64],
[70, 71, 72, 73, 74],
[80, 81, 82, 83, 84],
[90, 91, 92, 93, 94]])
You first have to transpose it
>>> narray=numpy.array([[x for x in xrange(i,i+5)] for i in xrange(0,100,10)])
>>> tarray=numpy.transpose(narray)
array([[ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90],
[ 1, 11, 21, 31, 41, 51, 61, 71, 81, 91],
[ 2, 12, 22, 32, 42, 52, 62, 72, 82, 92],
[ 3, 13, 23, 33, 43, 53, 63, 73, 83, 93],
[ 4, 14, 24, 34, 44, 54, 64, 74, 84, 94]])
and then convert to list
>>> larray=tarray.tolist()
>>> larray
[[0, 10, 20, 30, 40, 50, 60, 70, 80, 90], [1, 11, 21, 31, 41, 51, 61, 71, 81, 91], [2, 12, 22, 32, 42, 52, 62, 72, 82, 92], [3, 13, 23, 33, 43, 53, 63, 73, 83, 93], [4, 14, 24, 34, 44, 54, 64, 74, 84, 94]]
now you can index larray as larray[0], larray[1] to get the individual lists.
Given this
>>> a = array([[1,2,3,4], [5,6,7,8], [9, 10,11,12]])
>>> a
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
you can use slicing
>>> list1 = a[:,0]
>>> list1
array([1, 5, 9])
>>> list1 = a[:,1]
>>> list1
array([ 2, 6, 10])
a=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
list1=[]
list2=[]
list3=[]
list4=[]
for x in a:
for i,y in enumerate(x):
if i==0:
list1.append(y)
elif i==1:
list2.append(y)
elif i==2:
list3.append(y)
elif i==3:
list4.append(y)
>>> print(list1)
[1, 5, 9, 13]
>>> print(list2)
[2, 6, 10, 14]
>>> print(list3)
[3, 7, 11, 15]
>>> print(list4)
[4, 8, 12, 16]
Dynamically :
>>>a=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
>>>list=[[] for _ in range(len(a))]
>>>for x in a:
for i,y in enumerate(x):
list[i].append(y)
>>>print(list)
[[1, 5, 9, 13], [2, 6, 10, 14], [3, 7, 11, 15], [4, 8, 12, 16]]

Categories