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
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.
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]])
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]]
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
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