Cross-concatenate two matrices in tensorflow - python

Given two matrices, for example
[1 2] and [5 6]
[3 4] [7 8],
is there a way to concatenate them to get the following matrix?
[1 2 1 2]
[3 4 3 4]
[5 5 6 6]
[7 7 8 8]

NumPy based approach
Using array-initialization with broadcasted-assignment -
def assign_as_blocks(a,b):
m1,n1 = a.shape
m2,n2 = b.shape
out = np.empty((m1+m2,n2,n1),dtype=int)
out[:m1] = a[:,None,:]
out[m1:] = b[:,:,None]
return out.reshape(m1+m2,-1)
To let use tensorflow tools, a modified version would be :
def assign_as_blocks_v2(a,b):
shape1 = tf.shape(a)
shape2 = tf.shape(b)
m1 = shape1[0]
n1 = shape1[1]
m2 = shape2[0]
n2 = shape2[1]
p1 = tf.tile(a,[1,n2])
p2 = tf.reshape(tf.tile(tf.expand_dims(b, 1),[1,1,n1]), [m2,-1])
out = tf.concat((p1,p2),axis=0)
return out
Sample runs
Case #1 (Sample from question) :
In [95]: a
Out[95]:
array([[1, 2],
[3, 4]])
In [96]: b
Out[96]:
array([[5, 6],
[7, 8]])
In [97]: assign_as_blocks(a, b)
Out[97]:
array([[1, 2, 1, 2],
[3, 4, 3, 4],
[5, 5, 6, 6],
[7, 7, 8, 8]])
Case #2 (Generic shaped random array) :
In [106]: np.random.seed(0)
...: a = np.random.randint(0,9,(2,3))
...: b = np.random.randint(0,9,(4,5))
In [107]: a
Out[107]:
array([[5, 0, 3],
[3, 7, 3]])
In [108]: b
Out[108]:
array([[5, 2, 4, 7, 6],
[8, 8, 1, 6, 7],
[7, 8, 1, 5, 8],
[4, 3, 0, 3, 5]])
In [109]: assign_as_blocks(a, b)
Out[109]:
array([[5, 0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3, 5, 0, 3],
[3, 7, 3, 3, 7, 3, 3, 7, 3, 3, 7, 3, 3, 7, 3],
[5, 5, 5, 2, 2, 2, 4, 4, 4, 7, 7, 7, 6, 6, 6],
[8, 8, 8, 8, 8, 8, 1, 1, 1, 6, 6, 6, 7, 7, 7],
[7, 7, 7, 8, 8, 8, 1, 1, 1, 5, 5, 5, 8, 8, 8],
[4, 4, 4, 3, 3, 3, 0, 0, 0, 3, 3, 3, 5, 5, 5]])

>>> a = [[1,2],[3,4]]
>>> b = [[5,6],[7,8]]
>>> np.r_[np.kron([1,1],a),np.kron(b, [1,1])]
array([[1, 2, 1, 2],
[3, 4, 3, 4],
[5, 5, 6, 6],
[7, 7, 8, 8]])

Related

Is there an alternate way to do the same without for loop?

I have two numpy arrays A and l. The dimension of A is (n, x, y) and the dimension of l is (n,1). I get the result as follows:
res = []
for i in range(n):
res.append(A[i, x, l[i])
This way of getting the result is very time consuming for a larger value of n. Is there an alternative to get the same result quickly?
If 0<=l[i]<y for all values of i:
>>> n,x,y = 4,5,6
>>> A = np.random.randint(0,10,(n,x,y))
array([[[3, 3, 3, 8, 7, 0],
[8, 1, 1, 5, 3, 8],
[0, 1, 0, 4, 1, 3],
[2, 2, 1, 8, 6, 5],
[2, 5, 9, 2, 6, 3]],
[[9, 7, 4, 6, 7, 7],
[1, 7, 0, 4, 9, 6],
[8, 0, 8, 6, 7, 8],
[1, 9, 7, 8, 7, 6],
[2, 4, 6, 3, 6, 8]],
[[2, 8, 5, 7, 9, 4],
[7, 2, 2, 5, 2, 1],
[0, 8, 6, 4, 1, 2],
[6, 9, 9, 0, 2, 4],
[9, 9, 1, 6, 7, 0]],
[[3, 8, 4, 3, 5, 6],
[5, 3, 7, 7, 4, 6],
[9, 0, 7, 9, 2, 1],
[1, 6, 2, 2, 9, 5],
[5, 0, 9, 0, 5, 2]]])
>>> l = np.random.randint(low=0, high=y-1, size=(n,1))
array([[0],
[1],
[3],
[1]])
>>> x0 = 2
>>> res = []
>>> for i in range(n):
res.append(A[i, x0, l[i])
>>> res
[array([0]), array([0]), array([4]), array([0])]
numpy:
>>> A[range(n), 2, l.flatten()]
array([0, 0, 4, 0])
what about list comprehension?
res=[A[i, x, l[i] for i in range(n)]

Swap multiple indices in 2d array

Problem
For the following array:
import numpy as np
arr = np.array([[i for i in range(10)] for j in range(5)])
# arr example
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
For each row in arr, I'm attempting to swap n (in this case 2) indices according to some 2d array, such as.
swap = np.random.choice(arr.shape[1], [arr.shape[0], 2], replace=False)
# swap example
array([[8, 1],
[5, 0],
[7, 2],
[9, 4],
[3, 6]])
Question
I tried arr[:, swap] = arr[:, swap[:, ::-1]], but this performs every swap for each row, rather than only swapping indices row by row. The behaviour I am trying to achieve is given below. Is this possible without iterating over swap?
for idx, s in enumerate(swap):
arr[idx, s] = arr[idx, s[::-1]]
# new arr with indices swapped
array([[0, 8, 2, 3, 4, 5, 6, 7, 1, 9],
[5, 1, 2, 3, 4, 0, 6, 7, 8, 9],
[0, 1, 7, 3, 4, 5, 6, 2, 8, 9],
[0, 1, 2, 3, 9, 5, 6, 7, 8, 4],
[0, 1, 2, 6, 4, 5, 3, 7, 8, 9]])
You can to use a "helper" array to index arr. The helper coerces arr into the correct shape.
import numpy as np
arr = np.array([[i for i in range(10)] for j in range(5)])
swap = np.array([[8, 1], [5, 0], [7, 2], [9, 4], [3, 6]])
helper = np.arange(arr.shape[0])[:, None]
# helper is
# array([[0],
# [1],
# [2],
# [3],
# [4]])
# arr[helper] is
# array([[[0, 8, 2, 3, 4, 5, 6, 7, 1, 9]],
# [[5, 1, 2, 3, 4, 0, 6, 7, 8, 9]],
# [[0, 1, 7, 3, 4, 5, 6, 2, 8, 9]],
# [[0, 1, 2, 3, 9, 5, 6, 7, 8, 4]],
# [[0, 1, 2, 6, 4, 5, 3, 7, 8, 9]]])
arr[helper, swap] = arr[helper, swap[:, ::-1]]
# arr is
# array([[0, 8, 2, 3, 4, 5, 6, 7, 1, 9],
# [5, 1, 2, 3, 4, 0, 6, 7, 8, 9],
# [0, 1, 7, 3, 4, 5, 6, 2, 8, 9],
# [0, 1, 2, 3, 9, 5, 6, 7, 8, 4],
# [0, 1, 2, 6, 4, 5, 3, 7, 8, 9]])

Elementwise operations in numpy

I have a 4000 x 16 matrix A. I have 256 x 1 vector B. I need to get the elementwise addition for each element in A with every element of B and get a 3D array of size 4000 x 16 x 256. What is the most efficient way to achieve this without loops with numpy?
You can first reshape A to a 4000×16×1 matrix, and B to 1×1×256 matrix. Then you can perform addition:
A[:,:,None] + B.reshape(1, 1, -1)
For A a 4×5 matrix, and B a 3×1 matrix, for example, we get:
>>> A
array([[1, 2, 2, 2, 2],
[2, 1, 0, 3, 2],
[4, 1, 2, 1, 3],
[3, 2, 3, 2, 2]])
>>> B
array([[0],
[3],
[3],
[6],
[4],
[3]])
>>> A[:,:,None] + B.reshape(1, 1, -1)
array([[[ 1, 4, 4, 7, 5, 4],
[ 2, 5, 5, 8, 6, 5],
[ 2, 5, 5, 8, 6, 5],
[ 2, 5, 5, 8, 6, 5],
[ 2, 5, 5, 8, 6, 5]],
[[ 2, 5, 5, 8, 6, 5],
[ 1, 4, 4, 7, 5, 4],
[ 0, 3, 3, 6, 4, 3],
[ 3, 6, 6, 9, 7, 6],
[ 2, 5, 5, 8, 6, 5]],
[[ 4, 7, 7, 10, 8, 7],
[ 1, 4, 4, 7, 5, 4],
[ 2, 5, 5, 8, 6, 5],
[ 1, 4, 4, 7, 5, 4],
[ 3, 6, 6, 9, 7, 6]],
[[ 3, 6, 6, 9, 7, 6],
[ 2, 5, 5, 8, 6, 5],
[ 3, 6, 6, 9, 7, 6],
[ 2, 5, 5, 8, 6, 5],
[ 2, 5, 5, 8, 6, 5]]])
Performance: If I run the above 100 times with A a 4000×16 matrix, and B a 256×1 matrix of floating points, I get the following results:
>>> timeit(lambda: A[:,:,None] + B.reshape(1, 1, -1), number=100)
5.949456596048549
It thus takes roughly 59.49457ms for a single run. This looks reasonable to calculate 16'384'000 elements.
This is where numpy's broadcasting and np.transpose() features really shine!
A[:,:, np.newaxis] + B[np.newaxis,:,:].transpose(2,0,1)

How to get k top elements of multidimensional array along a axis instead of one that argmax gives

I have a prediction in the format of np.argmax(model.predict(X),axis=2) which returns one element.How to predict top k elements using numpy
The link provided by #desertnaut covers the 1D case. It is, however, not entirely trivial to generalize the good answer to "ND along axis".
Here is an example where we find the top 2 along axis 1:
>>> a = np.random.randint(0, 9, (3, 5, 6))
>>> b = a.argpartition(-2, axis=1)[:, -2:]
>>> i, j, k = a.shape
>>> i, j, k = np.ogrid[:i, :j, :k]
>>> b = b[i, a[i, b, k].argsort(axis=1), k]
>>> a
array([[[8, 4, 1, 2, 4, 8],
[0, 1, 3, 4, 2, 7],
[4, 2, 7, 8, 1, 4],
[1, 6, 2, 0, 3, 7],
[1, 0, 0, 2, 8, 1]],
[[1, 6, 3, 3, 0, 6],
[7, 2, 0, 3, 8, 5],
[5, 0, 1, 1, 7, 4],
[2, 2, 4, 2, 6, 2],
[5, 5, 7, 6, 8, 1]],
[[4, 4, 4, 6, 2, 5],
[2, 7, 8, 2, 6, 0],
[5, 6, 7, 5, 1, 6],
[6, 5, 3, 2, 2, 3],
[5, 1, 8, 1, 6, 8]]])
>>> a[i, b, k]
array([[[4, 4, 3, 4, 4, 7],
[8, 6, 7, 8, 8, 8]],
[[5, 5, 4, 3, 8, 5],
[7, 6, 7, 6, 8, 6]],
[[5, 6, 8, 5, 6, 6],
[6, 7, 8, 6, 6, 8]]])
A general function could look like
def argtopk(A, k, axis=0):
tk = A.argpartition(-k, axis=axis)[(*axis*(slice(None),), slice(-k, None))]
I = np.ogrid[(*map(slice, A.shape),)]
I[axis] = tk
I[axis] = A[I].argsort(axis=axis)
return tk[I]

How to get all submatrices of given size in numpy?

For example, x = np.random.randint(low=0, high=10, shape=(6,6)) gives me a 6x6 numpy array:
array([[3, 1, 0, 1, 5, 4],
[2, 9, 9, 4, 8, 8],
[2, 3, 4, 3, 2, 9],
[5, 8, 4, 5, 7, 6],
[3, 0, 8, 1, 8, 0],
[6, 7, 1, 9, 0, 5]])
How can I get a list of, say, all 2x3 submatrices? What about non-overlapping ones?
I could code this in myself, but I'm sure this is a common enough operation that it already exists in numpy, I just can't find it.
Listed in this post is a generic approach to get a list of submatrices with given shape. Based on the order of submatrices being row (C-style) or column major (fortran-way), you would have two choices. Here's the implementation with np.reshape , np.transpose and np.array_split -
def split_submatrix(x,submat_shape,order='C'):
p,q = submat_shape # Store submatrix shape
m,n = x.shape
if np.any(np.mod(x.shape,np.array(submat_shape))!=0):
raise Exception('Input array shape is not divisible by submatrix shape!')
if order == 'C':
x4D = x.reshape(-1,p,n/q,q).transpose(0,2,1,3).reshape(-1,p,q)
return np.array_split(x4D,x.size/(p*q),axis=0)
elif order == 'F':
x2D = x.reshape(-1,n/q,q).transpose(1,0,2).reshape(-1,q)
return np.array_split(x2D,x.size/(p*q),axis=0)
else:
print "Invalid output order."
return x
Sample run with a modified sample input -
In [201]: x
Out[201]:
array([[5, 2, 5, 6, 5, 6, 1, 5],
[1, 1, 8, 4, 4, 5, 2, 5],
[4, 1, 6, 5, 6, 4, 6, 1],
[5, 3, 7, 0, 5, 8, 6, 5],
[7, 7, 0, 6, 5, 2, 5, 4],
[3, 4, 2, 5, 0, 7, 5, 0]])
In [202]: split_submatrix(x,(3,4))
Out[202]:
[array([[[5, 2, 5, 6],
[1, 1, 8, 4],
[4, 1, 6, 5]]]), array([[[5, 6, 1, 5],
[4, 5, 2, 5],
[6, 4, 6, 1]]]), array([[[5, 3, 7, 0],
[7, 7, 0, 6],
[3, 4, 2, 5]]]), array([[[5, 8, 6, 5],
[5, 2, 5, 4],
[0, 7, 5, 0]]])]
In [203]: split_submatrix(x,(3,4),order='F')
Out[203]:
[array([[5, 2, 5, 6],
[1, 1, 8, 4],
[4, 1, 6, 5]]), array([[5, 3, 7, 0],
[7, 7, 0, 6],
[3, 4, 2, 5]]), array([[5, 6, 1, 5],
[4, 5, 2, 5],
[6, 4, 6, 1]]), array([[5, 8, 6, 5],
[5, 2, 5, 4],
[0, 7, 5, 0]])]

Categories