How to Broadcast Sum Vector and Tensor? - python

Suppose we have:
row vector V of shape (F,1), and
4-D tensor T of shape (N, F, X, Y).
As a concrete example, let N, F, X, Y = 2, 3, 2, 2. Let V = [v0, v1,v2].
Then, I want to element-wise add v0 to the inner 2x2 matrix T[0,0], v1 to T[0,1], and v2 to T[0,2]. Similarly, I want to add v0 to T[1,0], v1 to T[1,1], and v2 to T[1,2].
So at the "innermost" level, the addition between the 2x2 matrix and a scalar, e.g. T[0,0] + v0, uses broadcasting to element-wise add v0. Then what I'm trying to do is apply that more generally to each inner 2x2.
I've tried using np.einsum() and np.tensordot(), but I couldn't figure out what each of those functions was actually doing on a more fundamental level, so I wanted to ask for a more step-by-step explanation of how this computation might be done.
Thanks

To multiply: You can simply translate your text into indices names of eisnum and it will take care of broadcasting:
TV = np.einsum('ijkl,j->ijkl',T,V)
To add: Simply add dimensions to your V using None to match up last two dimensions of T and broadcasting will take care of the rest:
TV = T + V[:,None,None]
Example input/output that shows the desired behavior of your output for adding:
T:
[[[[7 4]
[5 9]]
[[0 3]
[2 6]]
[[7 6]
[1 1]]]
[[[8 0]
[8 7]]
[[2 6]
[9 2]]
[[8 6]
[4 9]]]]
V:
[0 1 2]
TV:
[[[[ 7 4]
[ 5 9]]
[[ 1 4]
[ 3 7]]
[[ 9 8]
[ 3 3]]]
[[[ 8 0]
[ 8 7]]
[[ 3 7]
[10 3]]
[[10 8]
[ 6 11]]]]

Related

How can I get a sublist with wraparound in Python

Simple 1D case
I would like to get a substring with wraparound.
str = "=Hello community of Python="
# ^^^^^ ^^^^^^^ I want this wrapped substring
str[-7]
> 'P'
str[5]
> 'o'
str[-7:5]
> ''
Why does this slice of a sequence starting at a negative index and ending in a positive one result in an empty string?
How would I get it to output "Python==Hell"?
Higher dimensional cases
In this simple case I could do some cutting and pasting, but in my actual application I want to get every sub-grid of size 2x2 of a bigger grid - with wraparound.
m = np.mat('''1 2 3;
4 5 6;
7 8 9''')
And I want to get all submatrices centered at some location (x, y), including '9 7; 3 1'. Indexing with m[x-1:y+1] doesn't work for (x,y)=(0,0), nor does (x,y)=(1,0) give 7 8; 1 2
3D example
m3d = np.array(list(range(27))).reshape((3,3,3))
>
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]],
[[18, 19, 20],
[21, 22, 23],
[24, 25, 26]]])
m3d[-1:1,-1:1,-1:1]
# doesn't give [[[26, 24], [20, 18]], [8, 6], [2, 0]]]
If need be I could write some code which gets the various sub-matrices and glues them back together, but this approach might get quite cumbersome when I have to apply the same method to 3d arrays.
I was hoping there would be an easy solution. Maybe numpy can help out here?
Using Advanced indexing (see the section starting with "From a 4x3 array the corner elements should be selected using advanced indexing"):
import numpy as np
m = np.mat('''1 2 3;
4 5 6;
7 8 9''')
print(m[np.ix_(range(-1, 1), range(-1, 1))])
print(m[np.ix_(range(-2, 2), range(-2, 2))])
print(m[np.arange(-2, 2)[:, np.newaxis], range(-2, 2)])
Output (Attempt This Online!):
[[9 7]
[3 1]]
[[5 6 4 5]
[8 9 7 8]
[2 3 1 2]
[5 6 4 5]]
[[5 6 4 5]
[8 9 7 8]
[2 3 1 2]
[5 6 4 5]]
Going through all sub-matrices
Since you want to go through all sub-matrices, we can beforehand separately prepare the row ranges and the column ranges, and then use pairs of them to quickly index:
import numpy as np
A = np.mat('''1 2 3;
4 5 6;
7 8 9''')
m, n = A.shape
rowranges = [
(np.arange(i, i+2) % m)[:, np.newaxis]
for i in range(m)
]
colranges = [
np.arange(j, j+2) % n
for j in range(n)
]
for rowrange in rowranges:
for colrange in colranges:
print(A[rowrange, colrange])
Output (Attempt This Online!):
[[1 2]
[4 5]]
[[2 3]
[5 6]]
[[3 1]
[6 4]]
[[4 5]
[7 8]]
[[5 6]
[8 9]]
[[6 4]
[9 7]]
[[7 8]
[1 2]]
[[8 9]
[2 3]]
[[9 7]
[3 1]]
3D case
m3d = np.array(list(range(27))).reshape((3,3,3))
m3d[np.ix_(range(-1,1), range(-1,1), range(-1,1))]
Output:
array([[[26, 24],
[20, 18]],
[[ 8, 6],
[ 2, 0]]])
Simply combine the two halfs yourself:
>>> str[-7:]+str[:5]
'Python==Hell'
You could repeat your data enough so that you don't need wraparound.
Substrings of length 3:
s = 'Python'
r = 3
s2 = s + s[:r-1]
for i in range(len(s)):
print(s2[i:i+r])
Output:
Pyt
yth
tho
hon
onP
nPy
Sub-matrices of size 2×2:
import numpy as np
m = np.mat('''1 2 3;
4 5 6;
7 8 9''')
r = 2
m2 = np.tile(m, (2, 2))
for i in range(3):
for j in range(3):
print(m2[i:i+r, j:j+r])
Output (Attempt This Online!):
[[1 2]
[4 5]]
[[2 3]
[5 6]]
[[3 1]
[6 4]]
[[4 5]
[7 8]]
[[5 6]
[8 9]]
[[6 4]
[9 7]]
[[7 8]
[1 2]]
[[8 9]
[2 3]]
[[9 7]
[3 1]]
For larger more-dimensional arrays, the simple np.tile adds mmore than necessary. You really just need to increase the size by + r-1 in each dimension, not by * 2. Like I did with the string. Not sure how to do that well with arrays. Plus I think you can also make your negative indexes work, so we just need someone to come along and do that.

How use np.take when the indices is an multiD array

There are two array, a and indices.
a's shape: (g,N), which means there are g group all with N samples.
indices' shape: (q,g), which means there are q class', each of them contains different indices for the g groups to access a's values.
For example,
a = [[1 3 7 8]
[2 4 5 6]] # shape:(2,4), 2 groups with 4 samples
indices = [[0 1]
[2 2]] # shape:(2,2), 2 class' with indices to access a for the two groups.
I try to use np.take(a, indices, axis=1)and get
result = [[[1 3]
[7 7]]
[[2 4]
[5 5]]]
but that wasn't what I want.
The result I want to get is:
result = [[1,4]
[7,5]]
because
indices[0] = [0,1] # class 0's indices for the two groups
a[0,0] = 1
a[1,1] = 4
indices[1] = [2,2] # class 1's indices for the two groups
a[0,2] = 7
a[1,2] = 5
Could anyone help? thanks!
Use take_along_axis:
np.take_along_axis(a.T,indices,0)
# array([[1, 4],
# [7, 5]])

how to duplicate each row of a matrix N times Numpy

I have a matrix with these dimensions (150,2) and I want to duplicate each row N times. I show what I mean with an example.
Input:
a = [[2, 3], [5, 6], [7, 9]]
suppose N= 3, I want this output:
[[2 3]
[2 3]
[2 3]
[5 6]
[5 6]
[5 6]
[7 9]
[7 9]
[7 9]]
Thank you.
Use np.repeat with parameter axis=0 as:
a = np.array([[2, 3],[5, 6],[7, 9]])
print(a)
[[2 3]
[5 6]
[7 9]]
r_a = np.repeat(a, repeats=3, axis=0)
print(r_a)
[[2 3]
[2 3]
[2 3]
[5 6]
[5 6]
[5 6]
[7 9]
[7 9]
[7 9]]
To create an empty multidimensional array in NumPy (e.g. a 2D array m*n to store your matrix), in case you don't know m how many rows you will append and don't care about the computational cost Stephen Simmons mentioned (namely re-building the array at each append), you can squeeze to 0 the dimension to which you want to append to: X = np.empty(shape=[0, n]).
This way you can use for example (here m = 5 which we assume we didn't know when creating the empty matrix, and n = 2):
import numpy as np
n = 2
X = np.empty(shape=[0, n])
for i in range(5):
for j in range(2):
X = np.append(X, [[i, j]], axis=0)
print X
which will give you:
[[ 0. 0.]
[ 0. 1.]
[ 1. 0.]
[ 1. 1.]
[ 2. 0.]
[ 2. 1.]
[ 3. 0.]
[ 3. 1.]
[ 4. 0.]
[ 4. 1.]]
If your input is a vector, use atleast_2d first.
a = np.atleast_2d([2, 3]).repeat(repeats=3, axis=0)
print(a)
# [[2 3]
# [2 3]
# [2 3]]

Vectorized Update numpy array using another numpy array elements as index

Let A,C and B be numpy arrays with the same number of rows.
I want to update 0th element of A[0], 2nd element of A[1] etc. That is, update B[i]th element of A[i] to C[i]
import numpy as np
A = np.array([[1,2,3],[3,4,5],[5,6,7],[0,8,9],[3,7,5]])
B = np.array([0,2,1,2,0])
C = np.array([8,9,6,5,4])
for i in range(5):
A[i, B[i]] = C[i]
print ("FOR", A)
A = np.array([[1,2,3],[3,4,5],[5,6,7],[0,8,9],[3,7,5]])
A[:,B[:]] = C[:]
print ("Vectorized, A", A)
Output:
FOR [[8 2 3]
[3 4 9]
[5 6 7]
[0 8 5]
[4 7 5]]
Vectorized, A [[4 6 5]
[4 6 5]
[4 6 5]
[4 6 5]
[4 6 5]]
The for loop and vectorization gave different results.
I am unsure how to vectorize this for loop using Numpy.
The reason that your approach doesn't work is that you're passing the whole B as the column index and replace them with C instead you need to specify both row index and column index. Since you just want to change the first 4 rows you can simply use np.arange(4) to select the rows B[:4] the columns and C[:4] the replacement items.
In [26]: A[np.arange(4),B[:4]] = C[:4]
In [27]: A
Out[27]:
array([[8, 2, 3],
[3, 4, 9],
[5, 6, 7],
[0, 8, 5],
[3, 7, 5]])
Note that if you wanna update the whole array, as mentioned in comments by #Warren you can use following approach:
A[np.arange(A.shape[0]), B] = C

Sorted Index Function of a vector in Tensorflow

I have a vector and i want to have the "Sorted Index Function" of it.
What i mean by that is, that if you have a vector v with k=length(v) and you sort it with
sort_v=tf.nn.top_k(v,k)
then i would like to have the "Sorted Index Function" psi with
v(psi(i))=sort_v(i)
how do i get this function (as a tensor) in tensorflow?
According to the documentation tf_nn.top_k returns both values and indices of the sorted tensor, so you can simply use two variables, one for the values and one for the indices
a_sorted_val, a_sorted_ind = tf.nn.top_k(a, 2)
a_sorted_ind is the fuction expressed as a tensor
Example:
import tensorflow as tf
import numpy as np
with tf.Session():
a = tf.convert_to_tensor([[4, 3, 2, 1], [5, 6, 7, 8]])
a_sort_val, a_sort_ind = tf.nn.top_k(a, 4)
values = a_sort_val.eval()
indices = a_sort_ind.eval()
unsorted_a = a.eval()
print(unsorted_a)
print(values)
print(indices)
type(a_sort_ind)
[[4 3 2 1] <-- unsorted
[5 6 7 8]]
[[4 3 2 1] <-- sorted tensor
[8 7 6 5]]
[[0 1 2 3] <-- indices of sorted tensor
[3 2 1 0]]
tensorflow.python.framework.ops.Tensor

Categories

Resources