JunShern Chan
JunShern Chan

Reputation: 179

Numpy choose: shape-mismatch error

I wish to shuffle between two pairs of numpy arrays, for example given

a = [a1,a2,a3,a4]
a_next = [a2,a3,a4,a5]
b = [b1,b2,b3,b4]
b_next [b2,b3,b4,b5]

I want to shuffle between a and b to get

x = [a1,b2,b3,a4]
x_next = [a2,b3,b4,a5]
y = [b1,a2,a3,b4]
y_next = [b2,a3,a4,b5]

I have managed to get this working for single-dimensional a and b, using:

a = np.array([11,22,33,44])
a_next = np.array([22,33,44,55])
b = np.array([10,20,30,40])
b_next = np.array([20,30,40,50])

choices = [a,b]
choices_next = [a_next,b_next]
alternating_indices = np.random.randint(0, 2, len(a)) # Random 0s or 1s

x = np.choose(alternating_indices, choices)
x_next = np.choose(alternating_indices, choices_next)
y = np.choose(1-alternating_indices, choices)
y_next = np.choose(1-alternating_indices, choices_next)

But my real a and b are actually 3D arrays (so a1, a2, ..., b1, b2 are of shape [width, height]) which gives the error ValueError: shape mismatch: objects cannot be broadcast to a single shape. Here's a toy example which gives the same error:

a = np.array([[11,11],[22,22],[33,33],[44,44]])
a_next = np.array([[22,22],[33,33],[44,44],[55,55]])
b = np.array([[10,10],[20,20],[30,30],[40,40]])
b_next = np.array([[20,20],[30,30],[40,40],[50,50]])

So, how can I make this work for arrays with elements of non-trivial shape? The real arrays a, a_next, b and b_next are of equal shape [M, width, height].

Thanks in advance!

Upvotes: 1

Views: 197

Answers (2)

Gianluca Micchi
Gianluca Micchi

Reputation: 1653

tl;dr: You can concatenate the arrays that interest you, then shuffle them and slice them:

c = np.concatenate((a, b))
np.random.shuffle(c)
x, y = c[:N], c[N:]

Slightly longer explanation:

From the arrays a and b you can create c = np.concatenate((a, b)) that returns the array c = np.array([a1, a2, a3, a4, b1, b2, b3, b4]), then shuffle it in place using the function np.random.shuffle(c). Now c will look something like c = np.array([a3, b1, a2, b2, a4, a1, b3, b4]). Finally, You can create the arrays x and y by slicing c in two parts. Assuming that the length of the array x you want to create is N < M, the array x can be created doing x = c[:N] and y by y = c[N:].

Upvotes: 0

user707650
user707650

Reputation:

Use boolean indexing on the first axis. The following

import numpy as np

a = np.array([[11,11],[22,22],[33,33],[44,44]])
b = np.array([[10,10],[20,20],[30,30],[40,40]])
ind = np.random.randint(0, 2, len(a), dtype=np.bool)

a[ind,...], b[ind,...] = b[ind,...], a[ind,...]

print(a)
print(b)

gives

[[10 10]
 [22 22]
 [33 33]
 [40 40]]
[[11 11]
 [20 20]
 [30 30]
 [44 44]]

for, in this case,

ind = [ True False False  True]

Upvotes: 2

Related Questions