Numpy - is there a way to specify broadcasting dimension? - python

Broadcasting is only possible (as far as I know) with matrices matching shape from the end (shape [4,3,2] is broadcastable with shapes [2], [3,2], [4,3,2]). But why?
Consider the following example:
np.zeros([4,3,2])
[[[0 0]
[0 0]
[0 0]]
[[0 0]
[0 0]
[0 0]]
[[0 0]
[0 0]
[0 0]]
[[0 0]
[0 0]
[0 0]]]
Why broadcasting with [1,2,3], or [1,2,3,4] isn't possible?
Adding with [1,2,3] (shape: [3], target shape: [4,3,2]) expected result:
[[[1 1]
[2 2]
[3 3]]
[[1 1]
[2 2]
[3 3]]
[[1 1]
[2 2]
[3 3]]
[[1 1]
[2 2]
[3 3]]]
Adding with [1,2,3,4] (shape: [4], target shape: [4,3,2]) expected result:
[[[1 1]
[1 1]
[1 1]]
[[2 2]
[2 2]
[2 2]]
[[3 3]
[3 3]
[3 3]]
[[4 4]
[4 4]
[4 4]]]
Or, if there would be concerns about multi dimensional broadcasting this way, adding with:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
(shape: [4,3], target shape: [4,3,2]) expected result:
[[[ 1 1]
[ 2 2]
[ 3 3]]
[[ 4 4]
[ 5 5]
[ 6 6]]
[[ 7 7]
[ 8 8]
[ 9 9]]
[[10 10]
[11 11]
[12 12]]]
So basically what I'm saying is that I can't see a reason why it couldn't find the matching shape, and do the operations respectively. If there's multiple dimensions matching in the target matrix, just select the last one automatically, or have the option to specify which dimension we want to perform the operation.
Any ideas/suggestions?

The broadcasting rules are simple and unambiguous.
add leading size 1 dimension as needed to match total number of dimensions
adjust all size 1 dimensions as needed to match
With (4,3,2)
(2,) => (1,1,2) => (4,3,2)
(3,2) => (1,3,2) => (4,3,2)
(3,) => (1,1,3) => (4,3,3) ERROR
(4,) => (1,1,4)
(4,3) => (1,4,3)
With reshape or np.newaxis we can add explicit new dimensions in the right place:
(3,1) => (1,3,1) => (4,3,2)
(4,1,1) => (4,3,2)
(4,3,1) => (4,3,2)
Why doesn't it do the last stuff automatically? Potential ambiguity. Without those rules, especially the 'add only leading', it would be possible to add the extra dimension in several different places.
e.g.
(2,3,3) + (3,) => is that (1,1,3) or (1,3,1)?
(2,3,3,3) + (3,3)

Related

How to Broadcast Sum Vector and Tensor?

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

Tensorflow: How to select rows from tensor with different size of indices?

From tensor a which size is [2,3,2]
a = [[[1 1]
[2 2]
[3 3]]
[[4 4]
[5 5]
[6 6]]]
I want to select rows with indices = [[0],[0,2]]
The expected output is:
b = [[[1 1]]
[[4 4]
[6 6]]]
I have tried tf.gather_nd but it cannot select rows if the size of indices is different.
Does that mean I cannot have a list of lists with different sizes as a tensor? If there's no way to get the expected result as a tensor b. Is there anyway get the result like this c?
c = [[[1 1]
[0 0]
[0 0]]
[[4 4]
[0 0]
[6 6]]]

How to do the product of arrays of an array in Python

In a single line, how can I get the product of the arrays of an array?
I need it to be done for multi columns cases
2 columns example:
X = [[1 4]
[2 3]
[0 2]
[1 5]
[3 1]
[3 6]]
sol = [4 6 0 5 3 18]
4 columns example:
X = [[1 4 2 3]
[2 3 1 5]
[0 2 3 4]
[1 5 2 2]
[3 1 1 6]
[3 6 3 1]]
sol = [24 30 0 20 18 54]
This is a row-wise multiplication. You can perform this with:
X.prod(axis=1)
for example:
>>> X
array([[1, 4],
[2, 3],
[0, 2],
[1, 5],
[3, 1],
[3, 6]])
>>> a.prod(axis=1)
array([ 4, 6, 0, 5, 3, 18])
You can also use numpy.multiply.reduce
np.multiply.reduce(x, axis=1)

Tensorflow embedding_lookup on multiple dimension

I would like to select a part of this tensor.
A = tf.constant([[[1,1],[2,2],[3,3]], [[4,4],[5,5],[6,6]]])
The output of A will be
[[[1 1]
[2 2]
[3 3]]
[[4 4]
[5 5]
[6 6]]]
The index I want to select from A is [1, 0]. I mean [2 2] of the first part and [4 4] of the second part of this tensor, so my expected result is
[2 2]
[4 4]
How can I do it with embedding_lookup function?
B = tf.nn.embedding_lookup(A, [1, 0])
I have already tried this
but it's not my expectation.
[[[4 4]
[5 5]
[6 6]]
[[1 1]
[2 2]
[3 3]]]
Can anyone help me and explain how to do it?
Try the following,
A = tf.constant([[[1,1],[2,2],[3,3]], [[4,4],[5,5],[6,6]]])
B = [1,0]
inds = [(a,b) for a,b in zip(np.arange(len(B)), B)]
C = tf.gather_nd(params=A, indices=inds)

Picking and assigning multiple subsets from multiple sets in numpy

Given base array X of shape (2, 3, 4) which can be interpreted as two sets of 3 elements each, where every element is 4-dimensional, I want to sample from this array X in the following way.
From each of 2 sets I want to pick 2 subsets each defined by the binary array of length 3, other subsets would be set to 0. So the sampling process is defined by the array of shape (2, 2, 3). The result of this sampling should have shape (2, 2, 3, 4).
Here's the code that does what I need but I wonder if it could be rewritten more efficiently using numpy indexing.
import numpy as np
np.random.seed(3)
sets = np.random.randint(0, 10, [2, 3, 4])
subset_masks = np.random.randint(0, 2, [2, 2, 3])
print('Base set\n', sets, '\n')
print('Subset masks\n', subset_masks, '\n')
result = np.empty([2, 2, 3, 4])
for set_index in range(sets.shape[0]):
for subset_index, subset in enumerate(subset_masks[set_index]):
print('----')
picked_subset = subset.reshape(3, 1) * sets[set_index]
result[set_index][subset_index] = picked_subset
print('Picking subset ', subset, 'from set #', set_index)
print(picked_subset, '\n')
Output
Base set
[[[8 9 3 8]
[8 0 5 3]
[9 9 5 7]]
[[6 0 4 7]
[8 1 6 2]
[2 1 3 5]]]
Subset masks
[[[0 0 1]
[1 0 0]]
[[1 0 1]
[0 1 1]]]
----
Picking subset [0 0 1] from set # 0
[[0 0 0 0]
[0 0 0 0]
[9 9 5 7]]
----
Picking subset [1 0 0] from set # 0
[[8 9 3 8]
[0 0 0 0]
[0 0 0 0]]
----
Picking subset [1 0 1] from set # 1
[[6 0 4 7]
[0 0 0 0]
[2 1 3 5]]
----
Picking subset [0 1 1] from set # 1
[[0 0 0 0]
[8 1 6 2]
[2 1 3 5]]
Extend each of them to 4D by adding new axis for subset_masks along the last one and for sets as the second axis. For adding those new axes, we can use None/np.newaxis. Then, leverage NumPy broadcasting to perform the element-wise multiplication, like so -
subset_masks[...,None]*sets[:,None]
Just for the kicks probably, we can also use np.einsum -
np.einsum('ijk,ilj->iljk',sets,subset_masks)

Categories

Resources